/*
 * wiringPi:
 *	Arduino look-a-like Wiring library for the Raspberry Pi
 *	Copyright (c) 2012-2017 Gordon Henderson
 *	Additional code for pwmSetClock by Chris Hall <chris@kchall.plus.com>
 *
 *	Thanks to code samples from Gert Jan van Loo and the
 *	BCM2835 ARM Peripherals manual, however it's missing
 *	the clock section /grr/mutter/
 ***********************************************************************
 * This file is part of wiringPi:
 *	https://projects.drogon.net/raspberry-pi/wiringpi/
 *
 *    wiringPi is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as
 *    published by the Free Software Foundation, either version 3 of the
 *    License, or (at your option) any later version.
 *
 *    wiringPi is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with wiringPi.
 *    If not, see <http://www.gnu.org/licenses/>.
 ***********************************************************************
 */

// Revisions:
//	19 Jul 2012:
//		Moved to the LGPL
//		Added an abstraction layer to the main routines to save a tiny
//		bit of run-time and make the clode a little cleaner (if a little
//		larger)
//		Added waitForInterrupt code
//		Added piHiPri code
//
//	 9 Jul 2012:
//		Added in support to use the /sys/class/gpio interface.
//	 2 Jul 2012:
//		Fixed a few more bugs to do with range-checking when in GPIO mode.
//	11 Jun 2012:
//		Fixed some typos.
//		Added c++ support for the .h file
//		Added a new function to allow for using my "pin" numbers, or native
//			GPIO pin numbers.
//		Removed my busy-loop delay and replaced it with a call to delayMicroseconds
//
//	02 May 2012:
//		Added in the 2 UART pins
//		Change maxPins to numPins to more accurately reflect purpose


#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include <poll.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <asm/ioctl.h>

#include <limits.h>
#include "softPwm.h"
#include "softTone.h"

#include "wiringPi.h"
#include "../version.h"

// Environment Variables

#define	ENV_DEBUG	"WIRINGPI_DEBUG"
#define	ENV_CODES	"WIRINGPI_CODES"
#define	ENV_GPIOMEM	"WIRINGPI_GPIOMEM"

int pwmmode = 0;

const char * int2bin(uint32_t param) {
	int bits = sizeof(uint32_t)*CHAR_BIT;
	static char buffer[sizeof(uint32_t)*CHAR_BIT + 1];
	char chars[2] = {'0', '1'};
	int i,j,offset;

        for (i = 0; i < bits; i++) {
		 j = bits - i - 1;
		 offset = (param & (1 << j)) >> j;
		 buffer[i] = chars[offset];
        }

	buffer[bits] = '\0';
	return buffer;
}

static int ORANGEPI_PIN_MASK_3[12][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,15,16,-1,18,-1,-1,21,22,23,24,25,26,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1, 3, 4, 5, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1, 2, 3,-1,-1,-1,-1, 8,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PL
};

static int ORANGEPI_PIN_MASK_LITE_2[12][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{ 0,-1, 2, 3,-1, 5,-1, 7, 8, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,21,22,23,24,25,26,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1, 3, 4, 5, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
};

static int ORANGEPI_PIN_MASK_ZERO[12][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6, 7,-1,-1,10,11,12,13,14,15,16,-1,18,19,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PL
};

static int ORANGEPI_PIN_MASK_ZERO_PLUS_2[12][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6,-1,-1,-1,-1,11,12,13,14,15,16,-1,18,19,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{ 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PL
};

static int ORANGEPI_PIN_MASK_WIN[12][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6, 7, 8, 9,10,11,12,13,14,15,16,-1,18,19,20,21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{ 0, 1, 2, 3, 4, 5, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{ 0, 1, 2, 3, 4, 5, 6,-1,-1,-1,-1,11,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1, 2, 3, 4, 5, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1, 2, 3,-1,-1,-1,-1,-1, 9,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PL
};

static int ORANGEPI_PIN_MASK_PRIME[9][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6, 7, 8, 9,10,11,12,13,14,15,16,-1,18,19,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1, 4, 5, 6, 7, 8, 9,10,11,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
};

static int ORANGEPI_PIN_MASK_PC_2[9][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6, 7, 8, 9,10,11,12,13,14,15,16,-1,18,19,-1,21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1, 4, 5, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
};

static int ORANGEPI_PIN_MASK_ZERO_PLUS[12][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3,-1,-1, 6, 7,-1,-1,10,11,12,13,14,15,16,-1,18,19,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PL
};

static int ORANGEPI_PIN_MASK_ZERO_2[12][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1, 1,-1,-1,-1, 5, 6, 7, 8, 9,10,11,-1,-1,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,16,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
};

static int ORANGEPI_PIN_MASK_ZERO_2_W[12][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
};

static int ORANGEPI_PIN_MASK_4A[12][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8,-1,-1,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PJ
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PK
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
};

static int ORANGEPI_PIN_MASK_800[5][32] =  //[BANK]	[INDEX]
{
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},
};

static int ORANGEPI_PIN_MASK_4[5][32] =  //[BANK]	[INDEX]
{
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PA
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PB
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PC
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
};

static int ORANGEPI_PIN_MASK_4_LTS[5][32] =  //[BANK]	[INDEX]
{
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PA
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PB
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PC
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
};

static int ORANGEPI_PIN_MASK_RK3399[5][32] =  //[BANK]	[INDEX]
{
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PA
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PB
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PC
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
};

static int ORANGEPI_PIN_MASK_5[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1, 4, 5,-1,-1,},//GPIO0
	{-1,-1,-1, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,  0, 1, 2,-1, 4,-1, 6,-1, -1,-1, 2, 3,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1, 4,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1, 3, 4,-1,-1,-1, -1,-1, 2, 3, 4,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_5B[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1, 4, 5,-1,-1,},//GPIO0
	{-1,-1,-1, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,  0, 1, 2,-1, 4,-1, 6,-1, -1,-1, 2, 3,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1, 3, 4,-1,-1,-1, -1,-1, 2, 3, 4,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_5PRO[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1, 6, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1, 2, 3,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1, 3, 4, 5, 6, 7, -1,-1, 2, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_CM5[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{-1,-1,-1,-1,-1,-1,-1,-1,  0, 1, 2, 3, 4, 5,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1, 2, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_CM5_TABLET[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1, 6, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1,  0, 1, 2, 3,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_5MAX[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6, 7,  0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1,-1, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6, 7,  0, 1, 2,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_5ULTRA[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6, 7,  0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1,-1, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6, 7,  0, 1, 2,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1, 6, 7, -1,-1,-1, 3,-1,-1,-1, 7,  0, 1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_5PLUS[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1, 7,  0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1,-1, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{ 0, 1, 2, 3, 4, 5,-1,-1, -1,-1,-1,-1,-1, 5, 6,-1, -1, 1, 2,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_AIMAX[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1, 5, 6, 7,  0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{-1,-1, 2, 3, 4,-1,-1, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{ 0, 1, 2, 3, 4, 5,-1,-1, -1,-1,-1,-1,-1, 5, 6,-1, -1, 1, 2,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_900[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1, 2, 3, 4,-1,-1, 7,  0, 1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{ 0, 1, 2, 3, 4, 5,-1,-1, -1,-1, 2, 3,-1, 5, 6,-1, -1, 1, 2,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_CM4[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,  0, 1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,  0, 1, 2, 3, 4, 5,-1, 7,},//GPIO3
	{ 0, 1, 2, 3, 4, 5, 6, 7,  0,-1, 2, 3, 4, 5,-1,-1,  0,-1,-1, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_RV[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1, 5, 6,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},
	{-1,-1,-1,-1,36,37,38,39, 40,-1,42,43,44,45,46,47, 48,49,50,51,52,53,54,55, 56,57,58,59,60,61,-1,63,},
};

static int ORANGEPI_PIN_MASK_3B[5][32] =  //[BANK]	[INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,  0, 1,-1,-1,-1,-1,-1,-1,},//GPIO0
	{ 0, 1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, 7,  0, 1, 2, 3, 4, 5, 6, 7,},//GPIO3
	{ 0, 1, 2, 3, 4, 5, 6,-1,  0,-1, 2, 3, 4, 5,-1,-1,  0,-1,-1, 3,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
};

static int ORANGEPI_PIN_MASK_R1_PLUS[5][32] =  //[BANK]	[INDEX]
{
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PA
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PB
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PC
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
	{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,},//PD
};

static int ORANGEPI_PIN_MASK_H3[9][32] =  //[BANK]  [INDEX]
{
	{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,-1,-1,-1,18,19,20,21,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PA
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PB
	{ 0, 1, 2, 3, 4,-1,-1, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PC
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,14,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PD
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PE
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PF
	{-1,-1,-1,-1,-1,-1, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PG
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PH
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//PI
};

static int ORANGEPI_PIN_MASK_3PLUS[16][32] =  //[BANK]  [INDEX]
{
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//31
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//63
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//95
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//127
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//159
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//191
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//223
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//255
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//287
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//319
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//351
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//383
	{-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,28,29,30,31,},//415
	{ 0, 1, 2, 3, 4, 5, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,31,},//447
	{ 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27,28,-1,30,31,},//479
	{ 0,-1, 2, 3,-1, 5, 6, 7, 8, 9,10,11,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,},//511
};

static int ORANGEPI_PIN_MASK_AIPRO[8][32] =  //[BANK]	[INDEX]
{
	{-1,-1, 2, 3,-1,-1, 6,-1, -1,-1,-1,-1,-1,-1,14,15, -1,-1,-1,-1,-1,-1,-1,-1, -1,25,-1,-1,-1,-1,-1,-1,},//GPIO0
	{-1, 1,-1,-1,-1,-1, 6,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO1
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,11,12,-1,-1,15, 16,17,18,19,20,-1,-1,-1, -1,25,26,27,28,-1,-1,-1,},//GPIO2
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO3
	{ 0,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO4
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO5
	{-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO6
	{-1,-1, 2, 3, 4, 5, 6, 7, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1,},//GPIO7
};

int (*ORANGEPI_PIN_MASK)[32];

// Extend wiringPi with other pin-based devices and keep track of
//	them in this structure

struct wiringPiNodeStruct *wiringPiNodes = NULL ;

// BCM Magic

#define	BCM_PASSWORD		0x5A000000


// The BCM2835 has 54 GPIO pins.
//	BCM2835 data sheet, Page 90 onwards.
//	There are 6 control registers, each control the functions of a block
//	of 10 pins.
//	Each control register has 10 sets of 3 bits per GPIO pin - the ALT values
//
//	000 = GPIO Pin X is an input
//	001 = GPIO Pin X is an output
//	100 = GPIO Pin X takes alternate function 0
//	101 = GPIO Pin X takes alternate function 1
//	110 = GPIO Pin X takes alternate function 2
//	111 = GPIO Pin X takes alternate function 3
//	011 = GPIO Pin X takes alternate function 4
//	010 = GPIO Pin X takes alternate function 5
//
// So the 3 bits for port X are:
//	X / 10 + ((X % 10) * 3)

// Port function select bits

#define	FSEL_INPT		0b000
#define	FSEL_OUTP		0b001
#define	FSEL_ALT0		0b100
#define	FSEL_ALT1		0b101
#define	FSEL_ALT2		0b110
#define	FSEL_ALT3		0b111
#define	FSEL_ALT4		0b011
#define	FSEL_ALT5		0b010

// Access from ARM Running Linux
//	Taken from Gert/Doms code. Some of this is not in the manual
//	that I can find )-:
//
// Updates in September 2015 - all now static variables (and apologies for the caps)
//	due to the Pi v2, v3, etc. and the new /dev/gpiomem interface

static volatile unsigned int GPIO_PADS ;
static volatile unsigned int GPIO_CLOCK_BASE ;

#ifndef CONFIG_ORANGEPI
static volatile unsigned int GPIO_BASE ;
#endif

static volatile unsigned int GPIO_TIMER ;
//static volatile unsigned int GPIO_PWM;

#define	PAGE_SIZE		(4*1024)
#define	BLOCK_SIZE		(4*1024)

#define MAP_SIZE 		4096UL
#define MAP_MASK 		(MAP_SIZE - 1)

static unsigned int usingGpioMem    = FALSE ;
static          int wiringPiSetuped = FALSE ;
static          int wiringPiSysSetuped = FALSE ;


// PWM
//	Word offsets into the PWM control region

#define	PWM_CONTROL 0
#define	PWM_STATUS  1
#define	PWM0_RANGE  4
#define	PWM0_DATA   5
#define	PWM1_RANGE  8
#define	PWM1_DATA   9

//	Clock regsiter offsets

#define	PWMCLK_CNTL	40
#define	PWMCLK_DIV	41

#define	PWM0_MS_MODE    0x0080  // Run in MS mode
#define	PWM0_USEFIFO    0x0020  // Data from FIFO
#define	PWM0_REVPOLAR   0x0010  // Reverse polarity
#define	PWM0_OFFSTATE   0x0008  // Ouput Off state
#define	PWM0_REPEATFF   0x0004  // Repeat last value if FIFO empty
#define	PWM0_SERIAL     0x0002  // Run in serial mode
#define	PWM0_ENABLE     0x0001  // Channel Enable

#define	PWM1_MS_MODE    0x8000  // Run in MS mode
#define	PWM1_USEFIFO    0x2000  // Data from FIFO
#define	PWM1_REVPOLAR   0x1000  // Reverse polarity
#define	PWM1_OFFSTATE   0x0800  // Ouput Off state
#define	PWM1_REPEATFF   0x0400  // Repeat last value if FIFO empty
#define	PWM1_SERIAL     0x0200  // Run in serial mode
#define	PWM1_ENABLE     0x0100  // Channel Enable

// Timer
//	Word offsets

#define	TIMER_LOAD	(0x400 >> 2)
#define	TIMER_VALUE	(0x404 >> 2)
#define	TIMER_CONTROL	(0x408 >> 2)
#define	TIMER_IRQ_CLR	(0x40C >> 2)
#define	TIMER_IRQ_RAW	(0x410 >> 2)
#define	TIMER_IRQ_MASK	(0x414 >> 2)
#define	TIMER_RELOAD	(0x418 >> 2)
#define	TIMER_PRE_DIV	(0x41C >> 2)
#define	TIMER_COUNTER	(0x420 >> 2)

// Locals to hold pointers to the hardware

static volatile unsigned int *gpio ;
static volatile unsigned int *pwm ;
static volatile unsigned int *clk ;
static volatile unsigned int *pads ;
//static volatile unsigned int *timer ;
//static volatile unsigned int *timerIrqRaw ;

// Export variables for the hardware pointers

volatile unsigned int *_wiringPiGpio ;
volatile unsigned int *_wiringPiPwm ;
volatile unsigned int *_wiringPiClk ;
volatile unsigned int *_wiringPiPads ;
volatile unsigned int *_wiringPiTimer ;
volatile unsigned int *_wiringPiTimerIrqRaw ;


// Data for use with the boardId functions.
//	The order of entries here to correspond with the PI_MODEL_X
//	and PI_VERSION_X defines in wiringPi.h
//	Only intended for the gpio command - use at your own risk!

// piGpioBase:
//	The base address of the GPIO memory mapped hardware IO

#define	GPIO_PERI_BASE_OLD	0x20000000
#define	GPIO_PERI_BASE_NEW	0x3F000000

static volatile unsigned int piGpioBase = 0 ;

// Time for easy calculations

static uint64_t epochMilli, epochMicro ;

// Misc

static int wiringPiMode = WPI_MODE_UNINITIALISED ;
static volatile int    pinPass = -1 ;
static pthread_mutex_t pinMutex ;

// Debugging & Return codes

int wiringPiDebug       = FALSE ;
//int wiringPiDebug     = TRUE ;
int wiringPiReturnCodes = FALSE ;

// Use /dev/gpiomem ?

int wiringPiTryGpioMem  = FALSE ;

sunxi_gpio_info sunxi_gpio_info_t;
rk3328_soc_info rk3328_soc_info_t;
rk3399_soc_info rk3399_soc_info_t;
rk3588_soc_info rk3588_soc_info_t;
rk3566_soc_info rk3566_soc_info_t;
s905d3_gpio_info s905d3_gpio_info_t;
a310b_gpio_info a310b_gpio_info_t;
jh7110_soc_info jh7110_soc_info_t;

// sysFds:
//	Map a file descriptor from the /sys/class/gpio/gpioX/value

static int sysFds[384] =
  {
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1-1,-1,-1,-1
  };

// ISR Data

static void (*isrFunctions [64])(void) ;


// Doing it the Arduino way with lookup tables...
//	Yes, it's probably more innefficient than all the bit-twidling, but it
//	does tend to make it all a bit clearer. At least to me!

// pinToGpio:
//	Take a Wiring pin (0 through X) and re-map it to the GPIO pin
//	Cope for 3 different board revisions here.

static int OrangePiModel;

static int *pinToGpio ;

int pinToGpio_3[64] =
{
	122, 121, 
	118, 354, 355, 
	120, 114, 119, 362, 111, 112, 
	229, 230, 117, 228, 227, 360,

	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   	  // ... 31
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_LITE_2[64] =
{
  230, 229, 
  228, 117, 118, 
  120, 73, 119, 122, 72, 71, 
  66, 67, 121, 64, 69, 227,

  // Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_ZERO[64] =
{
  12, 11, 6, 198, 199, 1, 7, 0,    // From the Original Wiki - GPIO 0 through 7:   wpi  0 -  7
   3, 19,               // I2C  - SDA0, SCL0                wpi  8 -  9
  18, 15,               // SPI  - CE1, CE0              wpi 10 - 11
  16,  2, 14,               // SPI  - MOSI, MISO, SCLK          wpi 12 - 14
  13, 10,               // UART - Tx, Rx                wpi 15 - 16
  -1, -1, -1, -1,           // Rev 2: New GPIOs 8 though 11         wpi 17 - 20
  -1, -1, -1, -1, -1,           // B+                       wpi 21, 22, 23, 24, 25
  -1, -1, -1, -1,           // B+                       wpi 26, 27, 28, 29
  -1,  1,               // B+                       wpi 30, 31

// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_H3[64] =
{
  12, 11, 6, 13, 14, 1, 110, 0,    // From the Original Wiki - GPIO 0 through 7:   wpi  0 -  7
   3,  68,               // I2C  - SDA0, SCL0                wpi  8 -  9
   71,  64,               // SPI  - CE1, CE0              wpi 10 - 11
  65,  2, 66,               // SPI  - MOSI, MISO, SCLK          wpi 12 - 14
  67, 21,               // UART - Tx, Rx                wpi 15 - 16
  19, 18, 7, 8,           // Rev 2: New GPIOs 8 though 11         wpi 17 - 20
  200,  9, 10, 201, 20,           // B+                       wpi 21, 22, 23, 24, 25
  198, 199,           //                       wpi 26, 27
  -1, -1,					//PA4, PA5(PWM0)		    wpi 28, 29

   -1, -1,               // B+                       wpi 30, 31

// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_ZERO_PLUS_2[64] =
{
  12, 11, 6, 0, 1, 352, 107, 353, 3,    // From the Original Wiki - GPIO 0 through 7:   wpi  0 -  7
   19,  18,               // I2C  - SDA0, SCL0                wpi  8 -  9
   15,  16,               // SPI  - CE1, CE0              wpi 10 - 11
   2,  14, 13,               // SPI  - MOSI, MISO, SCLK          wpi 12 - 14
  110, -1,               // UART - Tx, Rx                wpi 15 - 16
  -1, -1, -1, -1,           // Rev 2: New GPIOs 8 though 11         wpi 17 - 20
  -1, -1, -1, -1, -1,           // B+                       wpi 21, 22, 23, 24, 25
  -1, -1,           //                       wpi 26, 27
  -1, -1,					//PA4, PA5(PWM0)		    wpi 28, 29

// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_WIN[64] =
{
	227, 226,    // 0, 1
  	362, 354,    // 2, 3
	355, 229,    // 4  5
	100, 228,    // 6, 7
	231, 361,    // 8, 9
	 68,  98,    //10,11
	 99, 230,    //12,13
	 97,  96,    //14,15
	102, 143,    //16,17
	142,  36,    //18,19
	 37,  34,    //20,21
	 38,  39,    //22,23
	 35, 101,    //24,25
	 32,  33,    //26,27

	-1, -1,    //28,29
	-1, -1,    //30,31
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_PRIME[64] =
{
	12, 11,    // 0, 1
	6,  69,    // 2, 3
	70,  1,    // 4  5
	110, 0,    // 6, 7
	3,  68,    // 8, 9
	71, 15,    // 10,11
	16,  2,    // 12,13
	14, 13,    // 14,15
	72, 19,    // 16,17
	18,  7,    // 18,19
	8,  73,    // 20,21
	9,  10,    // 22,23
	74,107,    // 24,25
	75, 76,    // 26,27

	-1, -1,    // 28,29
	-1, -1,    // 30,31

	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
};

int pinToGpio_PC_2[64] =
{
	12, 11,     // 0, 1
	6, 69,     // 2, 3
	70,  1,    // 4  5
	110,0,     // 6, 7
	3, 68,    // 8, 9
	71, 15,    //10,11
	16,  2,    //12,13
	14, 13,    //14,15
	21, 19,     //16,17
	18, 7,     //18,19
	8, 200,    //20,21
	9, 10,     //22,23
	201,107,   //24,25
	198, 199,   //26,27

	-1, -1,    //28, 29
	-1, -1,    //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_ZERO_PLUS[64] =
{
	12, 11, 6, 198, 199, 1, 7, 0, 3,    // From the Original Wiki - GPIO 0 through 7:   wpi  0 -  7
	19,  18,               // I2C  - SDA0, SCL0                wpi  8 -  9
	15,  16,               // SPI  - CE1, CE0              wpi 10 - 11
	2,  14, 13,               // SPI  - MOSI, MISO, SCLK          wpi 12 - 14
	10, -1,               // UART - Tx, Rx                wpi 15 - 16
	-1, -1, -1, -1,           // Rev 2: New GPIOs 8 though 11         wpi 17 - 20
	-1, -1, -1, -1, -1,           // B+                       wpi 21, 22, 23, 24, 25
	-1, -1,           //                       wpi 26, 27
	-1, -1,					//PA4, PA5(PWM0)		    wpi 28, 29

	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int pinToGpio_ZERO_2[64] =
{
	229, 228, 73, 226, 227,  70,  75,
	 69,  72, 79,  78, 231, 232,  71,
	230, 233, 74,  65, 272, 262, 234,
	224, 225,

	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 				  	 // ... 31
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,           // ... 63
};

int pinToGpio_ZERO_2_W[64] =
{
	264, 263,      // 0, 1
	269, 224,     // 2, 3
	225, 226,      // 4  5
	257, 227,      // 6, 7
	261, 270,      // 8, 9
	228, 231,      //10,11
	232, 262,      //12,13
	230, 229,      //14,15
	233, 266,     //16,17
	265, 256,      //18,19
	271, 267,      //20,21
	268, 258,      //22,23
	 76, 272,      //24,25
	260, 259,      //26,27
	
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
};

int pinToGpio_4A[64] =
{
	257, 256,     // 0, 1
	 36,  45,     // 2, 3
	 46,  32,     // 4  5
	 37,  33,     // 6, 7
	 34, 269,     // 8, 9
	270, 260,     //10,11
	261, 262,     //12,13
	259, 258,     //14,15
	263, 265,     //16,17
	264,  35,     //18,19
	 43, 267,     //20,21
	268,  38,     //22,23
	266,  44,     //24,25
	 39,  40,     //26,27

	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
};

int pinToGpio_RK3399[64] =
{
	43,  44,      // 0, 1
	64,  148,      // 2, 3
	147, 80,      // 4  5
	65,  81,      // 6, 7
	82,  66,      // 8, 9
	67,  39,      //10,11
	40,  83,      //12,13
	41,  42,      //14,15
	133,  154,      //16,17
	50,  68,      //18,19
	69,  76,      //20,21
	70,  71,      //22,23
	73,  72,      //24,25
	74,  75,      //26,27
	
	-1,  -1,    //28,29
	-1,   -1,    //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63	
};

int pinToGpio_800[64] =
{
	43,   44, //0,1
	150,  39, //2,3
	40,  148, //4,5
	152, 147, //6,7
	149,  64, //8,9
	 65,  74, //10,11
	73,  153, //12,13
	75,   76, //14,15
	154,  -1, //16,17
	-1,   -1, //18,19
	-1,   -1, //20,21
	-1,   -1, //22,23
	-1,   -1, //24,25
	-1,   -1, //26,27
	-1,   -1, //28,29
	-1,   -1, //30,31
	-1,   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1,   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_4[64] =
{
	64,  65,      // 0, 1
	150, 145,      // 2, 3
	144, 33,      // 4  5
	50,  35,      // 6, 7
	92,  54,      // 8, 9
	55,  40,      //10,11
	39,  56,      //12,13
	41,  42,      //14,15
	149, 64,      //16,17
	65,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25

	
	-1,  -1,      //26,27
	
	-1,  -1,    //28,29
	-1,   -1,    //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63	
};

int pinToGpio_4_LTS[64] =
{
	52,  53,      // 0, 1
	150, 145,      // 2, 3
	144, 33,      // 4  5
	50,  35,      // 6, 7
	92,  54,      // 8, 9
	55,  40,      //10,11
	39,  56,      //12,13
	41,  42,      //14,15
	149, 64,      //16,17
	65,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25
	-1,  -1,      //26,27
	-1,  -1,    //28,29
	-1,   -1,    //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63	
};

int pinToGpio_5[64] =
{
	47,  46,      // 0, 1
	54, 131,      // 2, 3
	132,138,      // 4  5
	29, 139,      // 6, 7
	28,  59,      // 8, 9
	58,  49,      //10,11
	48,  92,      //12,13
	50,  52,      //14,15
	35,  -1,      //16,17
	-1,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25
	-1,  -1,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63	
};

int pinToGpio_5B[64] =
{
	47,  46,      // 0, 1
	54, 131,      // 2, 3
	132,138,      // 4  5
	29, 139,      // 6, 7
	28,  59,      // 8, 9
	58,  49,      //10,11
	48,  50,      //12,13
	52,  35,      //14,15
	-1,  -1,      //16,17
	-1,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25
	-1,  -1,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_5PRO[64] =
{
	59,  58,      // 0, 1
	47,  13,      // 2, 3
	14, 138,      // 4  5
	39, 139,      // 6, 7
	46,  33,      // 8, 9
	32,  42,      //10,11
	41,  40,      //12,13
	43,  44,      //14,15
	45,  34,      //16,17
	35,  36,      //18,19
	38,  62,      //20,21
	63, 135,      //22,23
	131,134,      //24,25
	132,133,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_CM5[64] =
{
	40,  41,      // 0, 1
	42,  43,      // 2, 3
	44,  45,      // 4  5
       138, 139,      // 6, 7
	-1,  -1,      // 8, 9
	-1,  -1,      //10,11
	-1,  -1,      //12,13
	-1,  -1,      //14,15
	-1,  -1,      //16,17
	-1,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25
	-1,  -1,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_CM5_TABLET[64] =
{
	47,  46,      // 0, 1
	35,  56,      // 2, 3
	57,  58,      // 4  5
	34,  59,      // 6, 7
	40,  36,      // 8, 9
	38,  42,      //10,11
	41,  39,      //12,13
	43,  44,      //14,15
	45,  -1,      //16,17
	-1,  -1,      //18,19
	-1,  -1,      //20,21
	-1,  -1,      //22,23
	-1,  -1,      //24,25
	-1,  -1,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_5MAX[64] =
{
	16,  15,      // 0, 1
	39,  13,      // 2, 3
	14,  32,      // 4  5
	134, 33,      // 6, 7
	34,  35,      // 8, 9
	36,  42,      //10,11
	41,  40,      //12,13
	43,  44,      //14,15
	45,  47,      //16,17
	46, 113,      //18,19
	109, 62,      //20,21
	110,114,      //22,23
	 63,135,      //24,25
	112,111,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_5ULTRA[64] =
{
	16,  15,      // 0, 1
	39,  13,      // 2, 3
	14,  32,      // 4  5
	134, 33,      // 6, 7
	34,  35,      // 8, 9
	36,  42,      //10,11
	41,  40,      //12,13
	43,  44,      //14,15
	45, 145,      //16,17
	144,113,      //18,19
	109,139,      //20,21
	110,114,      //22,23
	143,135,      //24,25
	112,111,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_5PLUS[64] =
{
	16,  15,      // 0, 1
	62,  33,      // 2, 3
	32,  36,      // 4  5
	97,  39,      // 6, 7
	40, 109,      // 8, 9
	110, 42,      //10,11
	41,  34,      //12,13
	43,  44,      //14,15
	45,  47,      //16,17
	46,  63,      //18,19
	96,  35,      //20,21
	114, 98,      //22,23
	101,113,      //24,25
	100, 99,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_AIMAX[64] =
{
	16,  15,      // 0, 1
	62,  13,      // 2, 3
	14,  36,      // 4  5
	97,  39,      // 6, 7
	40, 109,      // 8, 9
	110, 42,      //10,11
	41,  34,      //12,13
	43,  44,      //14,15
	45,  47,      //16,17
	46,  63,      //18,19
	96,  35,      //20,21
	114, 98,      //22,23
	101,113,      //24,25
	100, 99,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_900[64] =
{
        34,  35,      // 0, 1
        39,  46,      // 2, 3
        47, 101,      // 4  5
        97,  96,      // 6, 7
        113,107,      // 8, 9
        62,  42,      //10,11
        41,  63,      //12,13
        43,  44,      //14,15
        45,  32,      //16,17
        33,  36,      //18,19
        40, 114,      //20,21
        106, 98,      //22,23
        110,109,      //24,25
        100, 99,      //26,27
        -1,  -1,      //28,29
        -1,  -1,      //30,31

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_CM4[64] =
{
	140,141,      // 0, 1
	147, 25,      // 2, 3
	24, 118,      // 4  5
	119,128,      // 6, 7
	130,131,      // 8, 9
	129,138,      //10,11
	136,132,      //12,13
	139,134,      //14,15
	135, 32,      //16,17
	33, 133,      //18,19
	124,144,      //20,21
	127,120,      //22,23
	125,123,      //24,25
	122,121,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_3B[64] =
{
	140,141,      // 0, 1
	147, 25,      // 2, 3
	24, 118,      // 4  5
	119,128,      // 6, 7
	130,131,      // 8, 9
	129,138,      //10,11
	136,132,      //12,13
	139,134,      //14,15
	126, 32,      //16,17
	33, 133,      //18,19
	124,144,      //20,21
	127,120,      //22,23
	125,123,      //24,25
	122,121,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_RV[64] =
{
	58, 57,      // 0, 1
	55,  5,      // 2, 3
	6,  42,      // 4  5
	38, 43,      // 6, 7
	47, 54,      // 8, 9
	51, 52,      //10,11
	53, 50,      //12,13
	48, 49,      //14,15
	56, 45,      //16,17
	40, 37,      //18,19
	39, 46,      //20,21
	59, 63,      //22,23
	36, 60,      //24,25
	61, 44,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

int pinToGpio_R1_PLUS[64] =
{
        89,  88,      // 0, 1
       100, 102,      // 2, 3
       112, 103,      // 4  5
       101,  66,      // 6, 7
        -1,  -1,      // 8, 9
        -1,  -1,      //10,11
        -1,  -1,      //12,13
        -1,  -1,      //14,15
        -1,  -1,      //16,17
        -1,  -1,      //18,19
        -1,  -1,      //20,21
        -1,  -1,      //22,23
        -1,  -1,      //24,25
        -1,  -1,      //26,27
        -1,  -1,      //28,29
        -1,  -1,      //30,31

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
};

int pinToGpio_3PLUS[64] =
{
       415, 414,      // 0, 1
       487, 412,      // 2, 3
       413, 419,      // 4  5
       488, 421,      // 6, 7
       420, 451,      // 8, 9
       479, 447,      //10,11
       448, 417,      //12,13
       450, 449,      //14,15
       418, 416,      //16,17
       482, 478,      //18,19
       475, 480,      //20,21
       422, 489,      //22,23
       476, 483,      //24,25
       486, 485,      //26,27
       423,  -1,      //28,29
        -1,  -1,      //30,31

        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 63
};

int pinToGpio_AIPRO[64] =
{
	76,  75,      // 0, 1
	226, 14,      // 2, 3
	15,  82,      // 4  5
	227, 38,      // 6, 7
	79,  80,      // 8, 9
	25,  91,      //10,11
	92,   2,      //12,13
	89,  90,      //14,15
	83, 231,      //16,17
	84,  33,      //18,19
	128,228,      //20,21
	81,   3,      //22,23
	230,229,      //24,25
	-1,  -1,      //26,27
	-1,  -1,      //28,29
	-1,  -1,      //30,31

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ... 47
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,// ... 63
};

// physToGpio:
//	Take a physical pin (1 through 26) and re-map it to the GPIO pin
//	Cope for 2 different board revisions here.
//	Also add in the P5 connector, so the P5 pins are 3,4,5,6, so 53,54,55,56

static int *physToGpio ;

int physToGpio_3[64] =
{
	 -1,     	// 0
	 -1,  -1,	// 1, 2
	122,  -1,
	121,  -1,
	118, 354,
	 -1, 355,
	120, 114,
	119,  -1,
	362, 111,
	 -1, 112,
	229,  -1,
	230, 117,
	228, 227,
	 -1, 360,	// 25, 26

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	   // ... 42
	-1, -1, -1, -1, -1, -1, -1,	-1, -1, -1, -1, -1, -1, -1, -1, -1,    // ... 58
	-1, -1, -1, -1, -1,  											   // ... 63
};

int physToGpio_LITE_2[64] =
{
    -1,		// 0
    -1, -1,	// 1, 2
   230, -1,
   229, -1,
   228, 117,
    -1, 118,
   120, 73,
   119, -1,
   122, 72,
    -1, 71,
    66, -1,
    67, 121,
    64, 69,
    -1, 227,	// 25, 26

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_ZERO[64] =
{
  -1,       // 0
  -1, -1,   // 1, 2
  12, -1,
  11, -1,
   6,198,
  -1,199,
   1,  7,
   0, -1,
   3, 19,
  -1, 18,
  15, -1,
  16,  2,
  14, 13,
  -1, 10,   // 25, 26

  -1,  -1,   //27, 28
  -1,  -1,  //29, 30
  -1,  -1,  //31, 32
  -1, -1, //33, 34
  -1, -1, //35, 36
  -1, -1, //37, 38
  -1, -1, //39, 40
// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_H3[64] =
{
  -1,       // 0
  -1, -1,   // 1, 2
   12, -1,
   11, -1,
   6, 13,
  -1, 14,
   1, 110,
   0, -1,
   3, 68,
  -1, 71,
  64, -1,
  65,  2,
  66,  67,
  -1,  21,   // 25, 26

  19,  18,   //27, 28
  7,  -1,  //29, 30
  8,  200,  //31, 32
  9, -1, //33, 34
  10, 201, //35, 36
  20, 198, //37, 38
  -1, 199, //39, 40
   4, 5,   //41, 42
// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_ZERO_PLUS_2[64] =
{
  -1,       // 0
  -1, -1,   // 1, 2
   12, -1,
   11, -1,
   6, 0,
  -1, 1,
  352, 107,
  353, -1,
   3, 19,
  -1, 18,
  15, -1,
  16,  2,
  14,  13,
  -1,  110,   // 25, 26

  -1, -1,   //27, 28
  -1, -1,  //29, 30
  -1, -1,  //31, 32
  -1, -1, //33, 34
  -1, -1, //35, 36
  -1, -1, //37, 38
  -1, -1, //39, 40
  -1, -1,   //41, 42
// Padding:

  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_WIN[64] =
{
	-1,           // 0
	-1,     -1,   // 1, 2
	227,    -1,   // 3, 4
	226,    -1,   // 5, 6
	362,   354,   // 7, 8
	-1,    355,   // 9, 10
	229,   100,   //11, 12
	228,    -1,   //13, 14
	231,   361,   //15, 16
	-1,     68,   //17, 18
	98,     -1,   //19, 20
	99,    230,   //21, 22
	97,     96,   //23, 24
	-1,    102,   //25, 26
	143,   142,   //27, 28
	36,     -1,   //29, 30
	37,     34,   //31, 32
	38,     -1,   //33, 34
	39,     35,   //35, 36
	101,    32,   //37, 38
	-1,     33,   //39, 40
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //41-> 55
	-1, -1, -1, -1, -1, -1, -1, -1 // 56-> 63
};

int physToGpio_PRIME[64] =//head num map to OrangePi
{
	-1,          // 0
	-1,    -1,   // 1, 2
	12,    -1,   // 3, 4
	11,    -1,   // 5, 6
	6,     69,   // 7, 8
	-1,    70,   // 9, 10
	1,    110,   //11, 12
	0,     -1,   //13, 14
	3,     68,   //15, 16
	-1,    71,   //17, 18
	15,    -1,   //19, 20
	16,     2,   //21, 22
	14,    13,   //23, 24
	-1,    72,   //25, 26
	19,    18,   //27, 28
	7,     -1,   //29, 30
	8,     73,   //31, 32
	9,     -1,   //33, 34
	10,    74,   //35, 36
	107,   75,   //37, 38
	-1,    76,   //39, 40

	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //41-> 55
	-1, -1, -1, -1, -1, -1, -1, -1 // 56-> 63
};

int physToGpio_PC_2[64] =//head num map to OrangePi
{
	-1,          // 0
	-1,    -1,   // 1, 2
	12,    -1,   // 3, 4
	11,    -1,   // 5, 6
	6,     69,   // 7, 8
	-1,    70,   // 9, 10
	1,    110,   //11, 12
	0,     -1,   //13, 14
	3,     68,   //15, 16
	-1,    71,   //17, 18
	15,    -1,   //19, 20
	16,     2,   //21, 22
	14,    13,   //23, 24
	-1,    21,   //25, 26
	19,    18,   //27, 28
	7,     -1,   //29, 30
	8,    200,   //31, 32
	9,     -1,   //33, 34
	10,   201,   //35, 36
	107,  198,   //37, 38
	-1,   199,   //39, 40
	
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //41-> 55
	-1, -1, -1, -1, -1, -1, -1, -1 // 56-> 63
};

int physToGpio_ZERO_PLUS[64] =
{
	-1,       // 0
	-1, -1,   // 1, 2
	12, -1,
	11, -1,
	6, 198,
	-1, 199,
	1,   7,
	0, -1,
	3, 19,
	-1, 18,
	15, -1,
	16,  2,
	14,  13,
	-1,  10,   // 25, 26

	-1, -1,   //27, 28
	-1, -1,  //29, 30
	-1, -1,  //31, 32
	-1, -1, //33, 34
	-1, -1, //35, 36
	-1, -1, //37, 38
	-1, -1, //39, 40
	-1, -1,   //41, 42
	
	// Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_ZERO_2[64] =
{
	 -1,	      // 0
	 -1,  -1,     // 1, 2
	229,  -1,
	228,  -1,
	 73, 226,
	 -1, 227,
	 70,  75,
	 69,  -1,
	 72,  79,
	 -1,  78,
	231,  -1,
	232,  71,
	230, 233,
	 -1,  74,     // 25, 26
	 65, 224,     // 27
	272, 225,     // 29
	262,  -1,     // 31
	234,  -1,     // 33

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 49
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_ZERO_2_W[64] =
{
	 -1,	 
	 -1,  -1,
	264,  -1,
	263,  -1,
	269, 224,
	 -1, 225,
	226, 257,
	227,  -1,
	261, 270,
	 -1, 228,
	231,  -1,
	232, 262,
	230, 229,
	 -1, 233,
	266, 265,
	256,  -1,
	271, 267,
	268,  -1,
	258,  76,
	272, 260,
	 -1, 259,

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	   // ... 56
	-1, -1, -1, -1, -1, -1, -1, 			 		   // ... 63
};

int physToGpio_4A[64] =
{
	 -1,
	 -1,  -1,
	257,  -1,
	256,  -1,
	 36,  45,
	 -1,  46,
	 32,  37,
	 33,  -1,
	 34, 269,
	 -1, 270,
	260,  -1,
	261, 262,
	259, 258,
	 -1, 263,
	265, 264,
	 35,  -1,
	 43, 267,
	268,  -1,
	 38, 266,
	 44,  39,
	 -1,  40,

	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,	   // ... 56
	-1, -1, -1, -1, -1, -1, -1, 			 		   // ... 63
};

int physToGpio_RK3399[64] =//head num map to OrangePi
{
	-1,       // 0
	-1, -1,   // 1, 2
	43, -1,   // 3, 4
	44, -1,   // 5, 6
	64, 148,   // 7, 8
	-1, 147,   // 9, 10
	80, 65,   // 11, 12
	81, -1,   // 13, 14
	82, 66,   // 15, 16
	-1, 67,   // 17, 18
	39, -1,   // 19, 20
	40, 83,   // 21, 22
	41, 42,   // 23, 24
	-1, 133,   // 25, 26
	154, 50,   // 27, 28
	68, -1,   // 29, 30
	69, 76,   // 31, 32
	70, -1,   // 33, 34
	71, 73,   // 35, 36
	72, 74,   // 37, 38
	-1, 75,   // 39, 40
// Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_800[64] =//head num map to OrangePi
{
	-1,       // 0
	-1, -1,   // 1, 2
	43, -1,   // 3, 4
	44, -1,   // 5, 6
	150, 39,   // 7, 8
	-1, 40,   // 9, 10
	148, 152,   // 11, 12
	147, -1,   // 13, 14
	149, 64,   // 15, 16
	-1,  65,   // 17, 18
	74, -1,   // 19, 20
	73, 153,   // 21, 22
	75, 76,   // 23, 24
	-1, 154,   // 25, 26
	-1, -1,   // 27, 28
	-1, -1,   // 29, 30
	-1, -1,   // 31, 32
	-1, -1,   // 33, 34
	-1, -1,   // 35, 36
	-1, -1,   // 37, 38
	-1, 75,   // 39, 40

// Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_4[64] =//head num map to OrangePi
{
	-1,       // 0
	-1, -1,   // 1, 2
	64, -1,   // 3, 4
	65, -1,   // 5, 6
	150, 145,   // 7, 8
	-1, 144,   // 9, 10
	33, 50,   // 11, 12
	35, -1,   // 13, 14
	92, 54,   // 15, 16
	-1, 55,   // 17, 18
	40, -1,   // 19, 20
	39, 56,   // 21, 22
	41, 42,   // 23, 24
	-1, 149,   // 25, 26
 	64, 65,   // 27, 28
	-1, -1,   // 29, 30
	-1, 76,   // 31, 32
	-1, -1,   // 33, 34
	-1, 73,   // 35, 36
	-1, 74,   // 37, 38
	-1, 75,   // 39, 40
// Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_4_LTS[64] =//head num map to OrangePi
{
	-1,       // 0
	-1, -1,   // 1, 2
	64, -1,   // 3, 4
	65, -1,   // 5, 6
	150, 145,   // 7, 8
	-1, 144,   // 9, 10
	33, 50,   // 11, 12
	35, -1,   // 13, 14
	92, 54,   // 15, 16
	-1, 55,   // 17, 18
	40, -1,   // 19, 20
	39, 56,   // 21, 22
	41, 42,   // 23, 24
	-1, 149,   // 25, 26
	-1, -1,   // 27, 28
	-1, -1,   // 29, 30
	-1, -1,   // 31, 32
	-1, -1,   // 33, 34
	-1, -1,   // 35, 36
	-1, -1,   // 37, 38
	-1, -1,   // 39, 40

//Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5[64] =
{
	-1,       // 0
	-1, -1,   // 1, 2
	47, -1,   // 3, 4
	46, -1,   // 5, 6
	54, 131,   // 7, 8
	-1, 132,   // 9, 10
	138, 29,   // 11, 12
	139, -1,   // 13, 14
	28, 59,   // 15, 16
	-1, 58,   // 17, 18
	49, -1,   // 19, 20
	48, 92,   // 21, 22
	50, 52,   // 23, 24
	-1, 35,   // 25, 26
	-1, -1,   // 27, 28
	-1, -1,   // 29, 30
	-1, -1,   // 31, 32
	-1, -1,   // 33, 34
	-1, -1,   // 35, 36
	-1, -1,   // 37, 38
	-1, -1,   // 39, 40

//Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5B[64] =
{
	-1,       // 0
	-1, -1,   // 1, 2
	47, -1,   // 3, 4
	46, -1,   // 5, 6
	54, 131,   // 7, 8
	-1, 132,   // 9, 10
	138, 29,   // 11, 12
	139, -1,   // 13, 14
	28, 59,   // 15, 16
	-1, 58,   // 17, 18
	49, -1,   // 19, 20
	48, -1,   // 21, 22
	50, 52,   // 23, 24
	-1, 35,   // 25, 26
	-1, -1,   // 27, 28
	-1, -1,   // 29, 30
	-1, -1,   // 31, 32
	-1, -1,   // 33, 34
	-1, -1,   // 35, 36
	-1, -1,   // 37, 38
	-1, -1,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5PRO[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	59,  -1,   // 3, 4
	58,  -1,   // 5, 6
	47,  13,   // 7, 8
	-1,  14,   // 9, 10
	138, 39,   // 11, 12
	139, -1,   // 13, 14
	46,  33,   // 15, 16
	-1,  32,   // 17, 18
	42,  -1,   // 19, 20
	41,  40,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	34,  35,   // 27, 28
	36,  -1,   // 29, 30
	38,  62,   // 31, 32
	63,  -1,   // 33, 34
	135,131,   // 35, 36
	134,132,   // 37, 38
	-1, 133,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_CM5[64] =
{
	-1,        // 0
	40,  41,   // 1, 2
	42,  43,   // 3, 4
	44,  45,   // 5, 6
       138, 139,   // 7, 8
	-1,  -1,   // 9, 10
	-1,  -1,   // 11, 12
	-1,  -1,   // 13, 14
	-1,  -1,   // 15, 16
	-1,  -1,   // 17, 18
	-1,  -1,   // 19, 20
	-1,  -1,   // 21, 22
	-1,  -1,   // 23, 24
	-1,  -1,   // 25, 26
	-1,  -1,   // 27, 28
	-1,  -1,   // 29, 30
	-1,  -1,   // 31, 32
	-1,  -1,   // 33, 34
	-1,  -1,   // 35, 36
	-1,  -1,   // 37, 38
	-1,  -1,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_CM5_TABLET[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	47,  -1,   // 3, 4
	46,  -1,   // 5, 6
	35,  56,   // 7, 8
	-1,  57,   // 9, 10
	58,  34,   // 11, 12
	59,  -1,   // 13, 14
	40,  36,   // 15, 16
	-1,  38,   // 17, 18
	42,  -1,   // 19, 20
	41,  39,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	-1,  -1,   // 27, 28
	-1,  -1,   // 29, 30
	-1,  -1,   // 31, 32
	-1,  -1,   // 33, 34
	-1,  -1,   // 35, 36
	-1,  -1,   // 37, 38
	-1,  -1,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5MAX[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	16,  -1,   // 3, 4
	15,  -1,   // 5, 6
	39,  13,   // 7, 8
	-1,  14,   // 9, 10
	32, 134,   // 11, 12
	33,  -1,   // 13, 14
	34,  35,   // 15, 16
	-1,  36,   // 17, 18
	42,  -1,   // 19, 20
	41,  40,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	47,  46,   // 27, 28
	113, -1,   // 29, 30
	109, 62,   // 31, 32
	110, -1,   // 33, 34
	114, 63,   // 35, 36
	135,112,   // 37, 38
	-1, 111,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5ULTRA[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	16,  -1,   // 3, 4
	15,  -1,   // 5, 6
	39,  13,   // 7, 8
	-1,  14,   // 9, 10
	32, 134,   // 11, 12
	33,  -1,   // 13, 14
	34,  35,   // 15, 16
	-1,  36,   // 17, 18
	42,  -1,   // 19, 20
	41,  40,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	145,144,   // 27, 28
	113, -1,   // 29, 30
	109,139,   // 31, 32
	110, -1,   // 33, 34
	114,143,   // 35, 36
	135,112,   // 37, 38
	-1, 111,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_5PLUS[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	16,  -1,   // 3, 4
	15,  -1,   // 5, 6
	62,  33,   // 7, 8
	-1,  32,   // 9, 10
	36,  97,   // 11, 12
	39,  -1,   // 13, 14
	40, 109,   // 15, 16
	-1, 110,   // 17, 18
	42,  -1,   // 19, 20
	41,  34,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	47,  46,   // 27, 28
	63,  -1,   // 29, 30
	96,  35,   // 31, 32
	114, -1,   // 33, 34
	98, 101,   // 35, 36
	113,100,   // 37, 38
	-1,  99,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_AIMAX[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	16,  -1,   // 3, 4
	15,  -1,   // 5, 6
	62,  13,   // 7, 8
	-1,  14,   // 9, 10
	36,  97,   // 11, 12
	39,  -1,   // 13, 14
	40, 109,   // 15, 16
	-1, 110,   // 17, 18
	42,  -1,   // 19, 20
	41,  34,   // 21, 22
	43,  44,   // 23, 24
	-1,  45,   // 25, 26
	47,  46,   // 27, 28
	63,  -1,   // 29, 30
	96,  35,   // 31, 32
	114, -1,   // 33, 34
	98, 101,   // 35, 36
	113,100,   // 37, 38
	-1,  99,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_900[64] =
{
        -1,        // 0
        -1,  -1,   // 1, 2
        34,  -1,   // 3, 4
        35,  -1,   // 5, 6
        39,  46,   // 7, 8
        -1,  47,   // 9, 10
       101,  97,   // 11, 12
        96,  -1,   // 13, 14
       113, 107,   // 15, 16
        -1,  62,   // 17, 18
        42,  -1,   // 19, 20
        41,  63,   // 21, 22
        43,  44,   // 23, 24
        -1,  45,   // 25, 26
        32,  33,   // 27, 28
        36,  -1,   // 29, 30
        40, 114,   // 31, 32
       106, -1,   // 33, 34
        98, 110,   // 35, 36
        109,100,   // 37, 38
        -1,  99,   // 39, 40

        //Padding:
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
        -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_CM4[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	140, -1,   // 3, 4
	141, -1,   // 5, 6
	147, 25,   // 7, 8
	-1,  24,   // 9, 10
	118,119,   // 11, 12
	128, -1,   // 13, 14
	130,131,   // 15, 16
	-1, 129,   // 17, 18
	138, -1,   // 19, 20
	136,132,   // 21, 22
	139,134,   // 23, 24
	-1, 135,   // 25, 26
	32,  33,   // 27, 28
	133, -1,   // 29, 30
	124,144,   // 31, 32
	127, -1,   // 33, 34
	120,125,   // 35, 36
	123,122,   // 37, 38
	-1, 121,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_RV[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	58,  -1,   // 3, 4
	57,  -1,   // 5, 6
	55,  25,   // 7, 8
	-1,  24,   // 9, 10
	42,  38,   // 11, 12
	43,  -1,   // 13, 14
	47,  54,   // 15, 16
	-1,  51,   // 17, 18
	52,  -1,   // 19, 20
	53,  50,   // 21, 22
	48,  49,   // 23, 24
	-1,  56,   // 25, 26
	45,  40,   // 27, 28
	37,  -1,   // 29, 30
	39,  46,   // 31, 32
	59,  -1,   // 33, 34
	63,  36,   // 35, 36
	60,  61,   // 37, 38
	-1,  44,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_3B[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	140, -1,   // 3, 4
	141, -1,   // 5, 6
	147, 25,   // 7, 8
	-1,  24,   // 9, 10
	118,119,   // 11, 12
	128, -1,   // 13, 14
	130,131,   // 15, 16
	-1, 129,   // 17, 18
	138, -1,   // 19, 20
	136,132,   // 21, 22
	139,134,   // 23, 24
	-1, 126,   // 25, 26
	32,  33,   // 27, 28
	133, -1,   // 29, 30
	124,144,   // 31, 32
	127, -1,   // 33, 34
	120,125,   // 35, 36
	123,122,   // 37, 38
	-1, 121,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_R1_PLUS[64] =//head num map to OrangePi
{
	-1,       // 0
	-1, -1,   // 1, 2
	89, 88,   // 3, 4
	100, 102, // 5, 6
	-1, -1,   // 7, 8
	-1, 112,  // 9, 10
	103,101,  // 11, 12
	 66, -1,  // 13, 14
	-1, -1,   // 15, 16
	-1, -1,   // 17, 18
	-1, -1,   // 19, 20
	-1, -1,   // 21, 22
	-1, -1,   // 23, 24
	-1, -1,   // 25, 26
 	-1, -1,   // 27, 28
	-1, -1,   // 29, 30
	-1, -1,   // 31, 32
	-1, -1,   // 33, 34
	-1, -1,   // 35, 36
	-1, -1,   // 37, 38
	-1, -1,   // 39, 40
// Padding:
  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
  -1, -1, -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_3PLUS[64] =
{
        -1,        // 0
        -1,  -1,   // 1, 2
       415,  -1,   // 3, 4
       414,  -1,   // 5, 6
       487, 412,   // 7, 8
        -1, 413,   // 9, 10
       419, 488,   // 11, 12
       421,  -1,   // 13, 14
       420, 451,   // 15, 16
        -1, 479,   // 17, 18
       447,  -1,   // 19, 20
       448, 417,   // 21, 22
       450, 449,   // 23, 24
        -1, 418,   // 25, 26
       416, 482,   // 27, 28
       478,  -1,   // 29, 30
       475, 480,   // 31, 32
       422,  -1,   // 33, 34
       489, 476,   // 35, 36
       483, 486,   // 37, 38
        -1, 485,   // 39, 40
       423,

        //Padding:
        -1,  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
        -1,  -1, -1, -1, -1, -1,   // ... 63
};

int physToGpio_AIPRO[64] =
{
	-1,        // 0
	-1,  -1,   // 1, 2
	76,  -1,   // 3, 4
	75,  -1,   // 5, 6
	226, 14,   // 7, 8
	-1,  15,   // 9, 10
	82, 227,   // 11, 12
	38,  -1,   // 13, 14
	79,  80,   // 15, 16
	-1,  25,   // 17, 18
	91,  -1,   // 19, 20
	92,   2,   // 21, 22
	89,  90,   // 23, 24
	-1,  83,   // 25, 26
	-1,  -1,   // 27, 28
	231, -1,   // 29, 30
	84,  33,   // 31, 32
	128, -1,   // 33, 34
	228, 81,   // 35, 36
	 3, 230,   // 37, 38
	-1, 229,   // 39, 40

	//Padding:
	-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,   // ... 56
	-1, -1, -1, -1, -1, -1, -1,   // ... 63
};

// gpioToGPFSEL:
//	Map a BCM_GPIO pin to it's Function Selection
//	control port. (GPFSEL 0-5)
//	Groups of 10 - 3 bits per Function - 30 bits per port

static uint8_t gpioToGPFSEL [] =
{
  0,0,0,0,0,0,0,0,0,0,
  1,1,1,1,1,1,1,1,1,1,
  2,2,2,2,2,2,2,2,2,2,
  3,3,3,3,3,3,3,3,3,3,
  4,4,4,4,4,4,4,4,4,4,
  5,5,5,5,5,5,5,5,5,5,
} ;


// gpioToShift
//	Define the shift up for the 3 bits per pin in each GPFSEL port

static uint8_t gpioToShift [] =
{
  0,3,6,9,12,15,18,21,24,27,
  0,3,6,9,12,15,18,21,24,27,
  0,3,6,9,12,15,18,21,24,27,
  0,3,6,9,12,15,18,21,24,27,
  0,3,6,9,12,15,18,21,24,27,
  0,3,6,9,12,15,18,21,24,27,
} ;


// gpioToGPSET:
//	(Word) offset to the GPIO Set registers for each GPIO pin

static uint8_t gpioToGPSET [] =
{
   7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
   8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
} ;

// gpioToGPCLR:
//	(Word) offset to the GPIO Clear registers for each GPIO pin

static uint8_t gpioToGPCLR [] =
{
  10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,
  11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
} ;


// gpioToGPLEV:
//	(Word) offset to the GPIO Input level registers for each GPIO pin

static uint8_t gpioToGPLEV [] =
{
  13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
  14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,
} ;


#ifdef notYetReady
// gpioToEDS
//	(Word) offset to the Event Detect Status

static uint8_t gpioToEDS [] =
{
  16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,
  17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,
} ;

// gpioToREN
//	(Word) offset to the Rising edge ENable register

static uint8_t gpioToREN [] =
{
  19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,
  20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
} ;

// gpioToFEN
//	(Word) offset to the Falling edgde ENable register

static uint8_t gpioToFEN [] =
{
  22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,
  23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,
} ;
#endif


// GPPUD:
//	GPIO Pin pull up/down register

#define	GPPUD	37

// gpioToPUDCLK
//	(Word) offset to the Pull Up Down Clock regsiter

static uint8_t gpioToPUDCLK [] =
{
  38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,
  39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,
} ;


// gpioToPwmALT
//	the ALT value to put a GPIO pin into PWM mode

static uint8_t gpioToPwmALT [] =
{
          0,         0,         0,         0,         0,         0,         0,         0,	//  0 ->  7
          0,         0,         0,         0, FSEL_ALT0, FSEL_ALT0,         0,         0, 	//  8 -> 15
          0,         0, FSEL_ALT5, FSEL_ALT5,         0,         0,         0,         0, 	// 16 -> 23
          0,         0,         0,         0,         0,         0,         0,         0,	// 24 -> 31
          0,         0,         0,         0,         0,         0,         0,         0,	// 32 -> 39
  FSEL_ALT0, FSEL_ALT0,         0,         0,         0, FSEL_ALT0,         0,         0,	// 40 -> 47
          0,         0,         0,         0,         0,         0,         0,         0,	// 48 -> 55
          0,         0,         0,         0,         0,         0,         0,         0,	// 56 -> 63
} ;


// gpioToPwmPort
//	The port value to put a GPIO pin into PWM mode

/*static uint8_t gpioToPwmPort [] =
{
          0,         0,         0,         0,         0,         0,         0,         0,	//  0 ->  7
          0,         0,         0,         0, PWM0_DATA, PWM1_DATA,         0,         0, 	//  8 -> 15
          0,         0, PWM0_DATA, PWM1_DATA,         0,         0,         0,         0, 	// 16 -> 23
          0,         0,         0,         0,         0,         0,         0,         0,	// 24 -> 31
          0,         0,         0,         0,         0,         0,         0,         0,	// 32 -> 39
  PWM0_DATA, PWM1_DATA,         0,         0,         0, PWM1_DATA,         0,         0,	// 40 -> 47
          0,         0,         0,         0,         0,         0,         0,         0,	// 48 -> 55
          0,         0,         0,         0,         0,         0,         0,         0,	// 56 -> 63

} ;*/

// gpioToGpClkALT:
//	ALT value to put a GPIO pin into GP Clock mode.
//	On the Pi we can really only use BCM_GPIO_4 and BCM_GPIO_21
//	for clocks 0 and 1 respectively, however I'll include the full
//	list for completeness - maybe one day...

#define	GPIO_CLOCK_SOURCE	1

// gpioToGpClkALT0:

static uint8_t gpioToGpClkALT0 [] =
{
          0,         0,         0,         0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0,         0,	//  0 ->  7
          0,         0,         0,         0,         0,         0,         0,         0, 	//  8 -> 15
          0,         0,         0,         0, FSEL_ALT5, FSEL_ALT5,         0,         0, 	// 16 -> 23
          0,         0,         0,         0,         0,         0,         0,         0,	// 24 -> 31
  FSEL_ALT0,         0, FSEL_ALT0,         0,         0,         0,         0,         0,	// 32 -> 39
          0,         0, FSEL_ALT0, FSEL_ALT0, FSEL_ALT0,         0,         0,         0,	// 40 -> 47
          0,         0,         0,         0,         0,         0,         0,         0,	// 48 -> 55
          0,         0,         0,         0,         0,         0,         0,         0,	// 56 -> 63
} ;

// gpioToClk:
//	(word) Offsets to the clock Control and Divisor register

static uint8_t gpioToClkCon [] =
{
         -1,        -1,        -1,        -1,        28,        30,        32,        -1,	//  0 ->  7
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1, 	//  8 -> 15
         -1,        -1,        -1,        -1,        28,        30,        -1,        -1, 	// 16 -> 23
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 24 -> 31
         28,        -1,        28,        -1,        -1,        -1,        -1,        -1,	// 32 -> 39
         -1,        -1,        28,        30,        28,        -1,        -1,        -1,	// 40 -> 47
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 48 -> 55
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 56 -> 63
} ;

static uint8_t gpioToClkDiv [] =
{
         -1,        -1,        -1,        -1,        29,        31,        33,        -1,	//  0 ->  7
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1, 	//  8 -> 15
         -1,        -1,        -1,        -1,        29,        31,        -1,        -1, 	// 16 -> 23
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 24 -> 31
         29,        -1,        29,        -1,        -1,        -1,        -1,        -1,	// 32 -> 39
         -1,        -1,        29,        31,        29,        -1,        -1,        -1,	// 40 -> 47
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 48 -> 55
         -1,        -1,        -1,        -1,        -1,        -1,        -1,        -1,	// 56 -> 63
} ;


/*
 * Functions
 *********************************************************************************
 */


/*
 * wiringPiFailure:
 *	Fail. Or not.
 *********************************************************************************
 */

int wiringPiFailure (int fatal, const char *message, ...)
{
  va_list argp ;
  char buffer [1024] ;

  if (!fatal && wiringPiReturnCodes)
    return -1 ;

  va_start (argp, message) ;
    vsnprintf (buffer, 1023, message, argp) ;
  va_end (argp) ;

  fprintf (stderr, "%s", buffer) ;
  exit (EXIT_FAILURE) ;

  return 0 ;
}


/*
 * setupCheck
 *	Another sanity check because some users forget to call the setup
 *	function. Mosty because they need feeding C drip by drip )-:
 *********************************************************************************
 */

static void setupCheck (const char *fName)
{
	if (!wiringPiSetuped)
	{
		fprintf (stderr, "%s: You have not called one of the wiringPiSetup\n"
				"  functions, so I'm aborting your program before it crashes anyway.\n", fName) ;
		exit (EXIT_FAILURE) ;
	}
}

/*
 * gpioMemCheck:
 *	See if we're using the /dev/gpiomem interface, if-so then some operations
 *	can't be done and will crash the Pi.
 *********************************************************************************
 */

static void usingGpioMemCheck (const char *what)
{
  if (usingGpioMem)
  {
    fprintf (stderr, "%s: Unable to do this when using /dev/gpiomem. Try sudo?\n", what) ;
    exit (EXIT_FAILURE) ;
  }
}

/*
 * piGpioLayout:
 *	Return a number representing the hardware revision of the board.
 *	This is not strictly the board revision but is used to check the
 *	layout of the GPIO connector - and there are 2 types that we are
 *	really interested in here. The very earliest Pi's and the
 *	ones that came after that which switched some pins ....
 *
 *	Revision 1 really means the early Model A and B's.
 *	Revision 2 is everything else - it covers the B, B+ and CM.
 *		... and the Pi 2 - which is a B+ ++  ...
 *		... and the Pi 0 - which is an A+ ...
 *
 *	The main difference between the revision 1 and 2 system that I use here
 *	is the mapping of the GPIO pins. From revision 2, the Pi Foundation changed
 *	3 GPIO pins on the (original) 26-way header - BCM_GPIO 22 was dropped and
 *	replaced with 27, and 0 + 1 - I2C bus 0 was changed to 2 + 3; I2C bus 1.
 *
 *	Additionally, here we set the piModel2 flag too. This is again, nothing to
 *	do with the actual model, but the major version numbers - the GPIO base
 *	hardware address changed at model 2 and above (not the Zero though)
 *
 *********************************************************************************
 */

void piGpioLayoutOops (const char *why)
{
	fprintf (stderr, "Oops: Unable to determine board revision from /etc/orangepi-release or /etc/armbian-release.\n") ;
	fprintf (stderr, " -> %s\n", why) ;
	fprintf (stderr, " ->  You'd best google the error to find out why.\n") ;
	exit (EXIT_FAILURE) ;
}

void piBoardId (int * model)
{
	FILE *cpuFd ;
	char line [40] ;
	char *c;
	char revision[40];
	unsigned int i = 0;

	if ((cpuFd = fopen ("/etc/orangepi-release", "r")) == NULL)
		if ((cpuFd = fopen ("/etc/armbian-release", "r")) == NULL)
			piGpioLayoutOops ("Unable to open /etc/orangepi-release or /etc/armbian-release.");

	while (fgets (line, 40, cpuFd) != NULL)
	if (strncmp (line, "BOARD=", 6) == 0)
		break ;

	fclose (cpuFd) ;

	if (strncmp (line, "BOARD=", 6) != 0)
		piGpioLayoutOops ("No \"Revision\" line") ;

	if (wiringPiDebug)
		printf ("piBoardId: Revision string: %s\n", line) ;

	// Chomp trailing CR/NL
	for (c = &line [strlen (line) - 1] ; (*c == '\n') || (*c == '\r') ; --c)
		*c = 0 ;

	// Need to work out if it's using the new or old encoding scheme:
	// Scan to the first character of the revision number
	for (c = line ; *c ; ++c)
    	if (*c == '=')
      		break ;

	if (*c != '=')
    	piGpioLayoutOops ("Revision line (no equal)");

	c++;
	for (i = 0; *c ; ++c)
		revision[i++] = *c;

	revision[i] = '.';

	if (wiringPiDebug)
		printf ("piBoardId: Board string: %s\n", revision) ;

	/**/ if (strncmp(revision, "orangepi3.",               10) == 0) { *model = PI_MODEL_3; }
	else if (strncmp(revision, "orangepi3-lts.",           14) == 0) { *model = PI_MODEL_3; }
	else if (strncmp(revision, "orangepioneplus.",         16) == 0) { *model = PI_MODEL_LTIE_2; }
	else if (strncmp(revision, "orangepilite2.", 	       14) == 0) { *model = PI_MODEL_LTIE_2; }
	else if (strncmp(revision, "orangepizero.",            13) == 0) { *model = PI_MODEL_ZERO; }
	else if (strncmp(revision, "orangepizerolts.",         16) == 0) { *model = PI_MODEL_ZERO; }
	else if (strncmp(revision, "orangepizero-lts.",        17) == 0) { *model = PI_MODEL_ZERO; }
	else if (strncmp(revision, "orangepir1.",              11) == 0) { *model = PI_MODEL_ZERO; }
	else if (strncmp(revision, "orangepi-r1.",             12) == 0) { *model = PI_MODEL_ZERO; }
	else if (strncmp(revision, "orangepipc.",              11) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepipcplus.",	       15) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepione.",             12) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepilite.",            13) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepiplus.",            13) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepiplue2e.",	       15) == 0) { *model = PI_MODEL_H3; }
	else if (strncmp(revision, "orangepizeroplus2h3.",     20) == 0) { *model = PI_MODEL_ZERO_PLUS_2; }
	else if (strncmp(revision, "orangepizeroplus2-h3.",    21) == 0) { *model = PI_MODEL_ZERO_PLUS_2; }
	else if (strncmp(revision, "orangepiwin.",             12) == 0) { *model = PI_MODEL_WIN; }
	else if (strncmp(revision, "orangepiwinplus.",         16) == 0) { *model = PI_MODEL_WIN; }
	else if (strncmp(revision, "orangepiprime.",	       14) == 0) { *model = PI_MODEL_PRIME; }
	else if (strncmp(revision, "orangepipc2.",             12) == 0) { *model = PI_MODEL_PC_2; }
	else if (strncmp(revision, "orangepizeroplus.",        17) == 0) { *model = PI_MODEL_ZERO_PLUS; }
	else if (strncmp(revision, "orangepizeroplus2h5.",     20) == 0) { *model = PI_MODEL_ZERO_PLUS_2; }
	else if (strncmp(revision, "orangepizeroplus2-h5.",    21) == 0) { *model = PI_MODEL_ZERO_PLUS_2; }
	else if (strncmp(revision, "orangepizero2.",           14) == 0) { *model = PI_MODEL_ZERO_2; }
	else if (strncmp(revision, "orangepizero2w.",          14) == 0) { *model = PI_MODEL_ZERO_2_W; }
	else if (strncmp(revision, "orangepizero3.",           14) == 0) { *model = PI_MODEL_ZERO_2; }
	else if (strncmp(revision, "orangepirk3399.",          15) == 0) { *model = PI_MODEL_RK3399; }
	else if (strncmp(revision, "orangepi-rk3399.",         16) == 0) { *model = PI_MODEL_RK3399; }
	else if (strncmp(revision, "orangepi800.",             12) == 0) { *model = PI_MODEL_800; }
	else if (strncmp(revision, "orangepi4.",               10) == 0) { *model = PI_MODEL_4; }
	else if (strncmp(revision, "orangepi4a.",              11) == 0) { *model = PI_MODEL_4A; }
	else if (strncmp(revision, "orangepi4-lts.",           14) == 0) { *model = PI_MODEL_4_LTS; }
	else if (strncmp(revision, "orangepir1plus.",          15) == 0) { *model = PI_MODEL_R1_PLUS; }
	else if (strncmp(revision, "orangepi-r1plus.",         16) == 0) { *model = PI_MODEL_R1_PLUS; }
	else if (strncmp(revision, "orangepir1plus-lts.",      18) == 0) { *model = PI_MODEL_R1_PLUS; }
	else if (strncmp(revision, "orangepi-r1plus-lts.",     20) == 0) { *model = PI_MODEL_R1_PLUS; }
	else if (strncmp(revision, "orangepi5.",               10) == 0) { *model = PI_MODEL_5; }
	else if (strncmp(revision, "orangepi5b.",              11) == 0) { *model = PI_MODEL_5B; }
	else if (strncmp(revision, "orangepi5pro.",            13) == 0) { *model = PI_MODEL_5_PRO; }
	else if (strncmp(revision, "orangepi5max.",            13) == 0) { *model = PI_MODEL_5_MAX; }
	else if (strncmp(revision, "orangepi5ultra.",          15) == 0) { *model = PI_MODEL_5_ULTRA; }
	else if (strncmp(revision, "orangepi5plus.",           14) == 0) { *model = PI_MODEL_5_PLUS; }
	else if (strncmp(revision, "orangepiaimax.",           14) == 0) { *model = PI_MODEL_AI_MAX; }
	else if (strncmp(revision, "orangepi900.",             12) == 0) { *model = PI_MODEL_900; }
	else if (strncmp(revision, "orangepicm5.",             12) == 0) { *model = PI_MODEL_CM5; }
	else if (strncmp(revision, "orangepicm5-tablet.",      19) == 0) { *model = PI_MODEL_CM5_TABLET; }
	else if (strncmp(revision, "orangepicm5_tablet.",      19) == 0) { *model = PI_MODEL_CM5_TABLET; }
	else if (strncmp(revision, "orangepicm4.",             12) == 0) { *model = PI_MODEL_CM4; }
	else if (strncmp(revision, "orangepi3b.",              11) == 0) { *model = PI_MODEL_3B; }
	else if (strncmp(revision, "orangepi3plus.",           14) == 0) { *model = PI_MODEL_3_PLUS; }
	else if (strncmp(revision, "orangepiaipro.",           14) == 0) { *model = PI_MODEL_AI_PRO; }
	else if (strncmp(revision, "orangepiaipro-20t.",       18) == 0) { *model = PI_MODEL_AI_PRO; }
	else if (strncmp(revision, "orangepikunpengpro.",      19) == 0) { *model = PI_MODEL_AI_PRO; }
	else if (strncmp(revision, "orangepirv.",              11) == 0) { *model = PI_MODEL_RV; }

	if (wiringPiDebug)
		printf("piBoardId: model = %d\n", *model);
}

/*
 * wpiPinToGpio:
 *	Translate a wiringPi Pin number to native GPIO pin number.
 *	Provided for external support.
 *********************************************************************************
 */

int wpiPinToGpio (int wpiPin)
{
  return pinToGpio [wpiPin & 63] ;
}


/*
 * physPinToGpio:
 *	Translate a physical Pin number to native GPIO pin number.
 *	Provided for external support.
 *********************************************************************************
 */

int physPinToGpio (int physPin)
{
  return physToGpio [physPin & 63] ;
}


/*
 * setPadDrive:
 *	Set the PAD driver value
 *********************************************************************************
 */

void setPadDrive (int group, int value)
{
  uint32_t wrVal ;

  if ((wiringPiMode == WPI_MODE_PINS) || (wiringPiMode == WPI_MODE_PHYS) || (wiringPiMode == WPI_MODE_GPIO))
  {
    if ((group < 0) || (group > 2))
      return ;

    wrVal = BCM_PASSWORD | 0x18 | (value & 7) ;
    *(pads + group + 11) = wrVal ;

    if (wiringPiDebug)
    {
      printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ;
      printf ("Read : %08X\n", *(pads + group + 11)) ;
    }
  }
}


/*
 * getAlt:
 *	Returns the ALT bits for a given port. Only really of-use
 *	for the gpio readall command (I think)
 *********************************************************************************
 */
int getAlt (int pin)
{
	int alt;

	pin &= 63;

	if (wiringPiMode == WPI_MODE_PINS)
		pin = pinToGpio [pin];
	else if (wiringPiMode == WPI_MODE_PHYS)
		pin = physToGpio [pin];
	else if (wiringPiMode != WPI_MODE_GPIO)
		return 0;

	alt = orangepi_get_gpio_mode(pin);

	return alt;
}

void print_pwm_reg()
{
    uint32_t val = readR(SUNXI_PWM_CTRL_REG);
    uint32_t val2 = readR(SUNXI_PWM_PERIOD);

    if (wiringPiDebug) {
#ifdef OPI
        printf("SUNXI_PWM_CTRL_REG: %s\n", int2bin(val));
        printf("SUNXI_PWM_PERIOD: %s\n", int2bin(val2));
#else
        printf("SUNXI_PWM_CTRL_REG: [%x]\n", val);
        printf("SUNXI_PWM_PERIOD: [%x]\n", val2);
#endif
    }
}

void sunxi_pwm_set_enable_v2(int en)
{
    int val = 0;

    // CLK
    val = readR(SUNXI_PWM_CLK_REG);

    if (en) {
        val |= (SUNXI_PWM_SCLK_GATING);
    } else {
        val &= ~(SUNXI_PWM_SCLK_GATING);
    }

    if (wiringPiDebug)
	 printf(">>function%s,no:%d,enable? :0x%x\n", __func__, __LINE__, val);

    writeR(val, SUNXI_PWM_CLK_REG);
    delay(1);
    val = readR(SUNXI_PWM_EN_REG);

    // EN
    if (en) {
        val |= (SUNXI_PWM_EN);
    } else {
        val &= ~(SUNXI_PWM_EN);
    }

    if (wiringPiDebug)
	 printf(">>function%s,no:%d,enable? :0x%x\n", __func__, __LINE__, val);

    writeR(val, SUNXI_PWM_EN_REG);
    delay(1);

    // debug
    print_pwm_reg();
}


void sunxi_pwm_set_enable(int en)
{
	int val = 0;

	switch (OrangePiModel)
	{
		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:

			if(SUNXI_PWM_TYPE == SUNXI_V2_PWM_TYPE) {
				sunxi_pwm_set_enable_v2(en);
				return;
			}

			val = readR(SUNXI_PWM_CTRL_REG);

			if (en) {
				val |= (SUNXI_PWM_EN | SUNXI_PWM_SCLK_GATING);
			} else {
				val &= ~(SUNXI_PWM_EN | SUNXI_PWM_SCLK_GATING);
			}

			if (wiringPiDebug)
				printf(">>function%s,no:%d,enable? :0x%x\n", __func__, __LINE__, val);

			writeR(val, SUNXI_PWM_CTRL_REG);
			delay(1);
			print_pwm_reg();

			break;

		case PI_MODEL_3_PLUS:

			val = readR(S905D3_PWM_MISC);

			if (en) {
				val |= (1 << S905D3_PWM_EN_0 | 1 << S905D3_PWM_EN_1);
			} else {
				val &= ~(1 << S905D3_PWM_EN_0 | 1 << S905D3_PWM_EN_1);
			}

			if (wiringPiDebug)
				printf(">>function%s,no:%d,enable? :0x%x\n", __func__, __LINE__, val);

			writeR(val, S905D3_PWM_MISC);

			break;

		default:
			break;
	}
}

void sunxi_pwm_set_mode(int mode)
{
    int val = 0;

    val = readR(SUNXI_PWM_CTRL_REG);
    mode &= 1; //cover the mode to 0 or 1

    if (mode) { //pulse mode
        val |= (SUNXI_PWM_MS_MODE | SUNXI_PWM_PUL_START);
        pwmmode = 1;
    } else { //cycle mode
        val &= ~(SUNXI_PWM_MS_MODE);  //0<<9  MS_mode
        pwmmode = 0;
    }
    val |= (SUNXI_PWM_ACT_STA);  //1<<8  ACT_HIGH

    if (wiringPiDebug)
        printf(">>function%s,no:%d,mode? :0x%x\n", __func__, __LINE__, val);

    writeR(val, SUNXI_PWM_CTRL_REG);
    delay(1);
    print_pwm_reg();
}

void orangepi_pwm_set_tone(int pin,int freq)
{
	int div = 0;
	unsigned int range = 0;
	unsigned int val = 0;
	unsigned int pwm_period = 0;
	//unsigned int pwm_high = 0;
	//unsigned int pwm_cur_prd = 0;
	//float duty_ratio = 0;

	if (wiringPiDebug)
		printf(">>func:%s no:%d\n", __func__, __LINE__);

	switch (OrangePiModel)
	{
		case PI_MODEL_5:
		case PI_MODEL_5B:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_AI_MAX:

			rk3588_set_pwm_reg(pin, &rk3588_soc_info_t);

			if (freq == 0)
				orangepi_pwm_set_act (pin, 0);  //Off
			else {
				//enable conlock
				val = readR(RK3588_CH_CTRL);
				val |= (1 << RK3588_CONLOCK);
				writeR(val, RK3588_CH_CTRL);
				delay(1);
				val = readR(RK3588_CH_CTRL);

				//modifine tone
				div = readR(RK3588_CH_CTRL);
				div = ((div & 0x00ff0000) >> RK3588_SCALE);  //The 16 ~ 23 bits determine the frequency division
				div = 2 * div;  //The actual frequency division value is (2 * div)
				range = 24000000 / (div * freq);  //The default pwm clock frequency is 24MHz

				if (range / 2 == 0) {
					fprintf(stderr,"gpio: The PWM frequency you set is too high to be possible\n");
					exit(1);
				}

				writeR(range,RK3588_CH_PERIOD_HPR);
				delay(1);
				writeR(range / 2,RK3588_CH_DUTY_LPR);

				//disable conlock
				val = readR(RK3588_CH_CTRL);
				val &= ~(1 << RK3588_CONLOCK);
				writeR(val, RK3588_CH_CTRL);
				delay(1);
				val = readR(RK3588_CH_CTRL);

				if (wiringPiDebug)
					printf("div:%d range:%d\n",div,range);
			}

			break;

		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:

			H618_set_pwm_reg(pin,&sunxi_gpio_info_t);

			if (freq == 0)
				orangepi_pwm_set_act(pin, 0);             // Off
			else {
				div = readR(SUNXI_PWM_CTRL_REG);
				div &= 0x00ff;  //The lower 8 bits determine the frequency division
				div += 1;       //The actual frequency division value is (div + 1)
				range = 24000000 / (div * freq);  //The default pwm clock frequency is 24MHz

				orangepi_pwm_set_period(pin,range);
				orangepi_pwm_set_act(pin, range / 2);

				if (wiringPiDebug)
					printf("div:%d range:%d\n",div,range);
			}

			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			if (freq == 0)
				orangepi_pwm_set_act(pin, 0);             // Off
			else {
				div = readR(S905D3_PWM_MISC);
				div = ((div & 0x7f00) >> 8);  //The 8~14 bits determine the frequency division
				div += 1;       //The actual frequency division value is (div + 1)
				range = 24000000 / (div * freq);  //The default pwm clock frequency is 24MHz

				if ((range / 2) == 0) {
					fprintf(stderr,"gpio: The PWM frequency you set is too high to be possible\n");
					exit(1);
				}

				val = readR(S905D3_PWM_DUTY_CYCLE);
				val &= 0x0;
				val = ((range/2) << 16) | (range/2);

				writeR(val,S905D3_PWM_DUTY_CYCLE);
				val = readR(S905D3_PWM_DUTY_CYCLE);

				if (wiringPiDebug)
					printf("div:%d range:%d val:%#x\n",div,range,val);
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			rk3566_set_pwm_reg(pin,&rk3566_soc_info_t);

			if (freq == 0)
				orangepi_pwm_set_act (pin, 0);  //Off
			else {
				//enable conlock
				val = readR(RK3566_CH_CTRL);
				val |= (1 << RK3566_CONLOCK);
				writeR(val, RK3566_CH_CTRL);
				delay(1);
				val = readR(RK3566_CH_CTRL);

				//modifine tone
				div = readR(RK3566_CH_CTRL);
				div = ((div & 0x00ff0000) >> RK3566_SCALE);  //The 16 ~ 23 bits determine the frequency division
				div = 2 * div;  //The actual frequency division value is (2 * div)
				range = 24000000 / (div * freq);  //The default pwm clock frequency is 24MHz

				if (range / 2 == 0) {
					fprintf(stderr,"gpio: The PWM frequency you set is too high to be possible\n");
					exit(1);
				}

				writeR(range,RK3566_CH_PERIOD_HPR);
				delay(1);
				writeR(range / 2,RK3566_CH_DUTY_LPR);

				//disable conlock
				val = readR(RK3566_CH_CTRL);
				val &= ~(1 << RK3566_CONLOCK);
				writeR(val, RK3566_CH_CTRL);
				delay(1);
				val = readR(RK3566_CH_CTRL);

				if (wiringPiDebug)
					printf("div:%d range:%d\n",div,range);
			}

			break;

		case PI_MODEL_AI_PRO:

			if (freq > 0 && freq <= 32000)
			{
				if (pin != 33) {
					printf("the pin you choose doesn't support hardware PWM\n");
					printf("OPI:you can select wiringPi pin 33 for PWM pin\n");
					printf("or you can use it in softPwm mode\n");
					return;
				}

				pwm_period = 150000000 / freq;
				orangepi_pwm_set_period(pin, pwm_period);
				orangepi_pwm_set_act(pin, pwm_period / 2);

				writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);

				//a310b_gpio_info_t.pwm_prd3_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_PRD3_OFFSET;
				//a310b_gpio_info_t.pwm_ch3_pwl_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWL_OFFSET;
				//a310b_gpio_info_t.pwm_ch3_pwh_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWH_OFFSET;

				//// 计算当前占空比
				//pwm_high =readR(a310b_gpio_info_t.pwm_ch3_pwh_phyaddr);
				//pwm_cur_prd = readR(a310b_gpio_info_t.pwm_prd3_phyaddr);
				//duty_ratio = pwm_high * 100 / pwm_cur_prd;

				//pwm_period = 150000000 / freq;
				//writeR(pwm_period, a310b_gpio_info_t.pwm_prd3_phyaddr);

				//// 设置频率时保持占空比不变
				//writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);
				//writeR(pwm_period * duty_ratio / 100, a310b_gpio_info_t.pwm_ch3_pwh_phyaddr);
			} else {
				printf("wiringop: pwm freq error!!! (1 ~ 32000hz)\n");
			}

			break;

		default:
			break;
	}
}

void sunxi_pwm_set_clk_v2(int clk)
{
    int val = 0;

    if (wiringPiDebug)
	printf(">>function%s,no:%d\n", __func__, __LINE__);

    sunxi_pwm_set_enable(0);
    val = readR( SUNXI_PWM_CTRL_REG);

    if (wiringPiDebug)
        printf("read reg val: 0x%x\n", val);

    //clear clk to 0
    val &= 0x0f00;

    clk = (clk - 1) < 0 ? 0 : (clk - 1);
    val |= (clk & 0xff); //todo check wether clk is invalid or not
    writeR(val, SUNXI_PWM_CTRL_REG);

    sunxi_pwm_set_enable(1);

    if (wiringPiDebug)
        printf(">>function%s,no:%d,clk? :0x%x\n", __func__, __LINE__, val);

    delay(1);
    print_pwm_reg();
}


void orangepi_pwm_set_clk(int pin,int clk)
{
	int val = 0;
	int regval = 0;

	if (wiringPiDebug)
		printf(">>func:%s no:%d\n", __func__, __LINE__);

	switch (OrangePiModel)
	{
		case PI_MODEL_5:
		case PI_MODEL_5B:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_AI_MAX:

			if ((clk < 2) || (clk > 512)) {
				fprintf (stderr, "gpio: clock must be between 2 and 512\n") ;
				exit (1) ;
			}

			rk3588_set_pwm_reg(pin,&rk3588_soc_info_t);

			if (clk == 512)
				val = 0;
			else
				val = clk / 2;

			//enable conlock
			regval = readR(RK3588_CH_CTRL);
			regval |= (1 << RK3588_CONLOCK);
			writeR(regval, RK3588_CH_CTRL);
			delay(1);
			regval = readR(RK3588_CH_CTRL);

			//modifine clk
			regval = regval = readR(RK3588_CH_CTRL);
			regval &= ~(0xff << RK3588_SCALE);
			regval |= (val << RK3588_SCALE);
			writeR(regval, RK3588_CH_CTRL);
			delay(1);
			regval = readR(RK3588_CH_CTRL);

			//disable conlock
			regval = readR(RK3588_CH_CTRL);
			regval &= ~(1 << RK3588_CONLOCK);
			writeR(regval, RK3588_CH_CTRL);
			delay(1);
			regval = readR(RK3588_CH_CTRL);

			break;

		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:

			if ((clk < 1) || (clk > 256)) {
				fprintf (stderr, "gpio: clock must be between 1 and 256\n") ;
				exit (1) ;
			}

			H618_set_pwm_reg(pin,&sunxi_gpio_info_t);

			if(SUNXI_PWM_TYPE == SUNXI_V2_PWM_TYPE) {
				sunxi_pwm_set_clk_v2(clk);
				return;
			}

			if (wiringPiDebug)
				printf(">>function%s,no:%d\n", __func__, __LINE__);

			// sunxi_pwm_set_enable(0);
			val = readR(SUNXI_PWM_CTRL_REG);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", val);

			//clear clk to 0
			val &= 0xf801f0;

			val |= ((clk & 0xf) << 15); //todo check wether clk is invalid or not
			writeR(val, SUNXI_PWM_CTRL_REG);

			sunxi_pwm_set_enable(1);

			if (wiringPiDebug)
				printf(">>function%s,no:%d,clk? :0x%x\n", __func__, __LINE__, val);

			delay(1);
			print_pwm_reg();

			break;

		case PI_MODEL_3_PLUS:

			if ((clk < 1) || (clk > 128)) {
				fprintf (stderr, "gpio: clock must be between 1 and 128\n") ;
				exit (1) ;
			}

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			if (wiringPiDebug)
				printf(">>function%s,no:%d\n", __func__, __LINE__);

			sunxi_pwm_set_enable(0);
			val = readR(S905D3_PWM_MISC);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", val);

			//clear clk to 0
			val &= ~(0x007f7f00);

			clk = (clk - 1) < 0 ? 0 : (clk - 1) ;
			val = val | (clk << S905D3_PWM_CLK_DIV_0) | (clk << S905D3_PWM_CLK_DIV_1);
			writeR(val, S905D3_PWM_MISC);

			sunxi_pwm_set_enable(1);

			if (wiringPiDebug)
				printf(">>function%s,no:%d,clk? :0x%x\n", __func__, __LINE__, val);

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if ((clk < 2) || (clk > 512)) {
				fprintf (stderr, "gpio: clock must be between 2 and 512\n") ;
				exit (1) ;
			}

			rk3566_set_pwm_reg(pin,&rk3566_soc_info_t);

			if (clk == 512)
				val = 0;
			else
				val = clk / 2;

			//enable conlock
			regval = readR(RK3566_CH_CTRL);
			regval |= (1 << RK3566_CONLOCK);
			writeR(regval, RK3566_CH_CTRL);
			delay(1);
			regval = readR(RK3566_CH_CTRL);

			//modifine clk
			regval = regval = readR(RK3566_CH_CTRL);
			regval &= ~(0xff << RK3566_SCALE);
			regval |= (val << RK3566_SCALE);
			writeR(regval, RK3566_CH_CTRL);
			delay(1);
			regval = readR(RK3566_CH_CTRL);

			//disable conlock
			regval = readR(RK3566_CH_CTRL);
			regval &= ~(1 << RK3566_CONLOCK);
			writeR(regval, RK3566_CH_CTRL);
			delay(1);
			regval = readR(RK3566_CH_CTRL);

			break;

		case PI_MODEL_AI_PRO:

			if (pin != 33)
			{
				printf("the pin you choose doesn't support hardware PWM\n");
				printf("OPI:you can select wiringPi pin 33 for PWM pin\n");
				printf("or you can use it in softPwm mode\n");
				return;
			}

			printf("wiringop: opiaipro pwm clock is 150M. Not support setting the clock!!!\n");

			break;

		default:
			break;
	}
}

/**
 * ch0 and ch1 set the same,16 bit period and 16 bit act
 */
int sunxi_pwm_get_period(void)
{
    uint32_t period_cys = 0;
    period_cys = readR(SUNXI_PWM_PERIOD);

    if (wiringPiDebug) {
        printf("periodcys: %d\n", period_cys);
    }

    period_cys &= 0xffff0000; //get period_cys
    period_cys = period_cys >> 16;

    if (wiringPiDebug)
        printf(">>func:%s,no:%d,period/range:%d", __func__, __LINE__, period_cys);

    delay(1);
    return period_cys;
}

int sunxi_pwm_get_act(void)
{
    uint32_t period_act = 0;

    period_act = readR(SUNXI_PWM_PERIOD); //get ch1 period_cys
    period_act &= 0xffff; //get period_act

    if (wiringPiDebug)
        printf(">>func:%s,no:%d,period/range:%d", __func__, __LINE__, period_act);

    delay(1);
    return period_act;
}

void orangepi_pwm_set_period(int pin, unsigned int period_cys)
{
	uint32_t val = 0;
	uint32_t ccr = 0;

	if (wiringPiDebug)
		printf(">>func:%s no:%d\n", __func__, __LINE__);

	switch (OrangePiModel)
	{
		case PI_MODEL_5:
		case PI_MODEL_5B:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_AI_MAX:

			rk3588_set_pwm_reg(pin, &rk3588_soc_info_t);

			ccr = readR(RK3588_CH_DUTY_LPR);

			if (period_cys < ccr) {
				fprintf (stderr, "gpio: ARR should be greater than or equal to CCR (%d)\n",ccr);
				exit(1);
			}

			//enable conlock
			val = readR(RK3588_CH_CTRL);
			val |= (1 << RK3588_CONLOCK);
			writeR(val, RK3588_CH_CTRL);
			delay(1);
			val = readR(RK3588_CH_CTRL);

			//modifine period
			writeR(period_cys, RK3588_CH_PERIOD_HPR);
			delay(1);
			val = readR(RK3588_CH_PERIOD_HPR);

			//disable conlock
			val = readR(RK3588_CH_CTRL);
			val &= ~(1 << RK3588_CONLOCK);
			writeR(val, RK3588_CH_CTRL);
			delay(1);
			val = readR(RK3588_CH_CTRL);

			break;

		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:

			if ((period_cys < 1) || (period_cys > 65536)) {
				fprintf (stderr, "gpio: range must be between 1 and 65536\n") ;
				exit (1) ;
			}

			H618_set_pwm_reg(pin,&sunxi_gpio_info_t);

			period_cys -= 1;
			period_cys &= 0xffff; //set max period to 2^16
			period_cys = period_cys << 16;
			val = readR(SUNXI_PWM_PERIOD);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", val);

			val &= 0x0000ffff;
			period_cys |= val;

			if (wiringPiDebug)
				printf("write reg val: 0x%x\n", period_cys);

			writeR(period_cys, SUNXI_PWM_PERIOD);
			delay(1);
			val = readR(SUNXI_PWM_PERIOD);

			if (wiringPiDebug)
				printf("readback reg val: 0x%x\n", val);

			print_pwm_reg();

			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			ccr = readR(S905D3_PWM_DUTY_CYCLE);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", ccr);

			ccr = ccr >> 16;

			if (period_cys < ccr) {
				fprintf (stderr, "gpio: ARR should be greater than or equal to CCR (%d)\n",ccr) ;
				exit(1);
			}

			val = (ccr << 16) | (period_cys - ccr);
			writeR(val,S905D3_PWM_DUTY_CYCLE);
			val = readR(S905D3_PWM_DUTY_CYCLE);

			if (wiringPiDebug)
				printf("readback reg val: 0x%x\n", val);

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			rk3566_set_pwm_reg(pin,&rk3566_soc_info_t);

			ccr = readR(RK3566_CH_DUTY_LPR);

			if (period_cys < ccr) {
				fprintf (stderr, "gpio: ARR should be greater than or equal to CCR (%d)\n",ccr);
				exit(1);
			}

			//enable conlock
			val = readR(RK3566_CH_CTRL);
			val |= (1 << RK3566_CONLOCK);
			writeR(val, RK3566_CH_CTRL);
			delay(1);
			val = readR(RK3566_CH_CTRL);

			//modifine period
			writeR(period_cys, RK3566_CH_PERIOD_HPR);
			delay(1);
			val = readR(RK3566_CH_PERIOD_HPR);

			//disable conlock
			val = readR(RK3566_CH_CTRL);
			val &= ~(1 << RK3566_CONLOCK);
			writeR(val, RK3566_CH_CTRL);
			delay(1);
			val = readR(RK3566_CH_CTRL);

			break;

		case PI_MODEL_AI_PRO:

			if (pin != 33)
			{
				printf("the pin you choose doesn't support hardware PWM\n");
				printf("OPI:you can select wiringPi pin 33 for PWM pin\n");
				printf("or you can use it in softPwm mode\n");
				return;
			}

			a310b_gpio_info_t.pwm_prd3_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_PRD3_OFFSET;
			a310b_gpio_info_t.pwm_ch3_pwl_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWL_OFFSET;

			writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);
			writeR(period_cys, a310b_gpio_info_t.pwm_prd3_phyaddr);

			break;

		default:
			break;
	}
}

void orangepi_pwm_set_act(int pin, int act_cys)
{
	uint32_t per0 = 0;
	uint32_t arr = 0;
	uint32_t pwm_period = 0;

	switch (OrangePiModel)
	{
		case PI_MODEL_5:
		case PI_MODEL_5B:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_AI_MAX:

			rk3588_set_pwm_reg(pin,&rk3588_soc_info_t);

			arr = readR(RK3588_CH_PERIOD_HPR);

			if ((unsigned int)act_cys > arr) {
				fprintf (stderr, "gpio: CCR should be less than or equal to ARR (%d)\n",arr) ;
				exit(1);
			}

			//enable conlock
			per0 = readR(RK3588_CH_CTRL);
			per0 |= (1 << RK3588_CONLOCK);
			writeR(per0, RK3588_CH_CTRL);
			delay(1);
			per0 = readR(RK3588_CH_CTRL);

			//modifine act
			writeR(act_cys, RK3588_CH_DUTY_LPR);
			delay(1);
			per0 = readR(RK3588_CH_DUTY_LPR);

			//disable conlock
			per0 = readR(RK3588_CH_CTRL);
			per0 &= ~(1 << RK3588_CONLOCK);
			writeR(per0, RK3588_CH_CTRL);
			delay(1);
			per0 = readR(RK3588_CH_CTRL);

			break;

		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:

			if ((act_cys < 0) || (act_cys > 65535)) {
				fprintf (stderr, "gpio: range must be between 0 and 65535\n");
				exit (1) ;
			}

			H618_set_pwm_reg(pin,&sunxi_gpio_info_t);

			arr = sunxi_pwm_get_period();

			if (wiringPiDebug)
				printf("==> no:%d period now is :%d,act_val to be set:%d\n", __LINE__, arr, act_cys);

			if ((uint32_t)act_cys > (arr+1)) {
				printf("val pwmWrite 0 <= X <= 1024\n");
				printf("Or you can set new range by yourself by pwmSetRange(range)\n");
				return;
			}

			//keep period the same, clear act_cys to 0 first
			if (wiringPiDebug)
				printf(">>func:%s no:%d\n", __func__, __LINE__);
			per0 = readR(SUNXI_PWM_PERIOD);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", per0);

			per0 &= 0xffff0000;
			act_cys &= 0xffff;
			act_cys |= per0;

			if (wiringPiDebug)
				printf("write reg val: 0x%x\n", act_cys);

			writeR(act_cys, SUNXI_PWM_PERIOD);
			delay(1);
			print_pwm_reg();

			break;

		case PI_MODEL_3_PLUS:

			if (wiringPiDebug)
				printf(">>func:%s no:%d\n", __func__, __LINE__);

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			per0 = readR(S905D3_PWM_DUTY_CYCLE);

			if (wiringPiDebug)
				printf("read reg val: 0x%x\n", per0);

			arr = ((per0 & 0xffff0000) >> 16) + (per0 & 0x0000ffff);

			if ((unsigned int)act_cys > arr) {
				fprintf (stderr, "gpio: CCR should be less than or equal to ARR (%d)\n",arr) ;
				exit(1);
			} else {
				per0 = arr - act_cys;
				act_cys &= 0xffff;
				act_cys = ((act_cys << 16) | per0);
				writeR(act_cys, S905D3_PWM_DUTY_CYCLE);
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			rk3566_set_pwm_reg(pin,&rk3566_soc_info_t);

			arr = readR(RK3566_CH_PERIOD_HPR);

			if ((unsigned int)act_cys > arr) {
				fprintf (stderr, "gpio: CCR should be less than or equal to ARR (%d)\n",arr) ;
				exit(1);
			}

			//enable conlock
			per0 = readR(RK3566_CH_CTRL);
			per0 |= (1 << RK3566_CONLOCK);
			writeR(per0, RK3566_CH_CTRL);
			delay(1);
			per0 = readR(RK3566_CH_CTRL);

			//modifine act
			writeR(act_cys, RK3566_CH_DUTY_LPR);
			delay(1);
			per0 = readR(RK3566_CH_DUTY_LPR);

			//disable conlock
			per0 = readR(RK3566_CH_CTRL);
			per0 &= ~(1 << RK3566_CONLOCK);
			writeR(per0, RK3566_CH_CTRL);
			delay(1);
			per0 = readR(RK3566_CH_CTRL);

			break;

		case PI_MODEL_AI_PRO:

			if (pin != 33)
			{
				printf("the pin you choose doesn't support hardware PWM\n");
				printf("OPI:you can select wiringPi pin 33 for PWM pin\n");
				printf("or you can use it in softPwm mode\n");
				return;
			}

			a310b_gpio_info_t.pwm_prd3_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_PRD3_OFFSET;
			a310b_gpio_info_t.pwm_ch3_pwl_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWL_OFFSET;
			a310b_gpio_info_t.pwm_ch3_pwh_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWH_OFFSET;

			pwm_period = readR(a310b_gpio_info_t.pwm_prd3_phyaddr);
			if (act_cys >= pwm_period || act_cys < 0)
			{
				printf("wiringop: error: value greater than period(%d)\n", pwm_period);
				return;
			}

			writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);
			writeR(pwm_period - act_cys, a310b_gpio_info_t.pwm_ch3_pwh_phyaddr);

			break;

		default:
			break;
	}
}


/*
 * pwmSetMode:
 *	Select the native "balanced" mode, or standard mark:space mode
 *********************************************************************************
 */

void pwmSetMode(int pin,int mode)
{
    if (OrangePiModel == PI_MODEL_ZERO_2 || OrangePiModel == PI_MODEL_ZERO_2_W) {
        H618_set_pwm_reg(pin,&sunxi_gpio_info_t);
    }

    sunxi_pwm_set_mode(mode);

    return;
}

/*
 * pwmSetRange:
 *	Set the PWM range register. We set both range registers to the same
 *	value. If you want different in your own code, then write your own.
 *********************************************************************************
 */

void pwmSetRange(int pin,unsigned int range)
{
	if ((pin & PI_GPIO_MASK) == 0) {
		if (wiringPiMode == WPI_MODE_PINS)
			pin = pinToGpio[pin];
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return;
	}

	if (-1 == pin) {
		printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", __func__,  __LINE__, pin);
		return;
	}

	orangepi_pwm_set_period(pin, range);
	return;
}

/*
 * pwmSetClock:
 *	Set/Change the PWM clock. Originally my code, but changed
 *	(for the better!) by Chris Hall, <chris@kchall.plus.com>
 *	after further study of the manual and testing with a 'scope
 *********************************************************************************
 */

void pwmSetClock(int pin,int divisor)
{
	if ((pin & PI_GPIO_MASK) == 0) {
		if (wiringPiMode == WPI_MODE_PINS)
			pin = pinToGpio[pin];
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return;
	}

	if (-1 == pin) {
		printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", __func__,  __LINE__, pin);
		return;
	}

	orangepi_pwm_set_clk(pin, divisor);

	return;
}

/*
 * gpioClockSet:
 *	Set the frequency on a GPIO clock pin
 *********************************************************************************
 */

void gpioClockSet (int pin, int freq)
{
  int divi, divr, divf ;

  pin &= 63 ;

  /**/ if (wiringPiMode == WPI_MODE_PINS)
    pin = pinToGpio [pin] ;
  else if (wiringPiMode == WPI_MODE_PHYS)
    pin = physToGpio [pin] ;
  else if (wiringPiMode != WPI_MODE_GPIO)
    return ;
  
  divi = 19200000 / freq ;
  divr = 19200000 % freq ;
  divf = (int)((double)divr * 4096.0 / 19200000.0) ;

  if (divi > 4095)
    divi = 4095 ;

  *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | GPIO_CLOCK_SOURCE ;		// Stop GPIO Clock
  while ((*(clk + gpioToClkCon [pin]) & 0x80) != 0)				// ... and wait
    ;

  *(clk + gpioToClkDiv [pin]) = BCM_PASSWORD | (divi << 12) | divf ;		// Set dividers
  *(clk + gpioToClkCon [pin]) = BCM_PASSWORD | 0x10 | GPIO_CLOCK_SOURCE ;	// Start Clock
}


/*
 * wiringPiFindNode:
 *      Locate our device node
 *********************************************************************************
 */

struct wiringPiNodeStruct *wiringPiFindNode (int pin)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  while (node != NULL)
    if ((pin >= node->pinBase) && (pin <= node->pinMax))
      return node ;
    else
      node = node->next ;

  return NULL ;
}


/*
 * wiringPiNewNode:
 *	Create a new GPIO node into the wiringPi handling system
 *********************************************************************************
 */

static         void pinModeDummy             (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int mode)  { return ; }
static         void pullUpDnControlDummy     (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int pud)   { return ; }
//static unsigned int digitalRead8Dummy        (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return 0 ; }
//static         void digitalWrite8Dummy       (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
static          int digitalReadDummy         (UNU struct wiringPiNodeStruct *node, UNU int UNU pin)            { return LOW ; }
static         void digitalWriteDummy        (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
static         void pwmWriteDummy            (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }
static          int analogReadDummy          (UNU struct wiringPiNodeStruct *node, UNU int pin)            { return 0 ; }
static         void analogWriteDummy         (UNU struct wiringPiNodeStruct *node, UNU int pin, UNU int value) { return ; }

struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins)
{
  int    pin ;
  struct wiringPiNodeStruct *node ;

// Minimum pin base is 64

  if (pinBase < 64)
    (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: pinBase of %d is < 64\n", pinBase) ;

// Check all pins in-case there is overlap:

  for (pin = pinBase ; pin < (pinBase + numPins) ; ++pin)
    if (wiringPiFindNode (pin) != NULL)
      (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Pin %d overlaps with existing definition\n", pin) ;

  node = (struct wiringPiNodeStruct *)calloc (sizeof (struct wiringPiNodeStruct), 1) ;	// calloc zeros
  if (node == NULL)
    (void)wiringPiFailure (WPI_FATAL, "wiringPiNewNode: Unable to allocate memory: %s\n", strerror (errno)) ;

  node->pinBase          = pinBase ;
  node->pinMax           = pinBase + numPins - 1 ;
  node->pinMode          = pinModeDummy ;
  node->pullUpDnControl  = pullUpDnControlDummy ;
  node->digitalRead      = digitalReadDummy ;
//node->digitalRead8     = digitalRead8Dummy ;
  node->digitalWrite     = digitalWriteDummy ;
//node->digitalWrite8    = digitalWrite8Dummy ;
  node->pwmWrite         = pwmWriteDummy ;
  node->analogRead       = analogReadDummy ;
  node->analogWrite      = analogWriteDummy ;
  node->next             = wiringPiNodes ;
  wiringPiNodes          = node ;

  return node ;
}


#ifdef notYetReady
/*
 * pinED01:
 * pinED10:
 *	Enables edge-detect mode on a pin - from a 0 to a 1 or 1 to 0
 *	Pin must already be in input mode with appropriate pull up/downs set.
 *********************************************************************************
 */

void pinEnableED01Pi (int pin)
{
  pin = pinToGpio [pin & 63] ;
}
#endif

/*
 *********************************************************************************
 * Core Functions
 *********************************************************************************
 */

/*
 * pinModeAlt:
 *	This is an un-documented special to let you set any pin to any mode
 *********************************************************************************
 */

void pinModeAlt (int pin, int mode)
{
  int fSel, shift ;

  setupCheck ("pinModeAlt") ;

/*
#ifdef CONFIG_ORANGEPI
#if !(defined CONFIG_ORANGEPI_RK3399 || defined CONFIG_ORANGEPI_4 || defined CONFIG_ORANGEPI_4_LTS || defined CONFIG_ORANGEPI_800 || defined CONFIG_ORANGEPI_R1PLUS || CONFIG_ORANGEPI_2G_IOT)
        if(version == ORANGEPI) {
                if (wiringPiDebug)
                        printf("PinModeAlt: pin:%d,mode:%d\n", pin, mode);
                if ((pin & PI_GPIO_MASK) == 0) {
                        if (wiringPiMode == WPI_MODE_PINS)
                                pin = pinToGpio[pin];
                        else if (wiringPiMode == WPI_MODE_PHYS)
                                pin = physToGpio[pin];
                        else if (wiringPiMode != WPI_MODE_GPIO)
                                  return;

                        if (-1 == pin) {
                                printf("[%s:L%d] the pin:%d is invaild,please check it over!\n",
                                                        __func__,  __LINE__, pin);
                                return;
                        }

			if ( mode <= 1 || mode >= 8){
                                printf("[%s:L%d] the mode:%d is invaild,please check it over!\n",
                                                        __func__,  __LINE__, mode);
				return;
			}

			orangepi_set_gpio_alt(pin, mode);

			return;
                } else {
                        return ;
                }
        }
#endif
#endif
*/

/*
  if ((pin & PI_GPIO_MASK) == 0)
  {
    if (wiringPiMode == WPI_MODE_PINS)
      pin = pinToGpio [pin] ;
    else if (wiringPiMode == WPI_MODE_PHYS)
      pin = physToGpio [pin] ;
    else if (wiringPiMode != WPI_MODE_GPIO)
      return ;

    fSel  = gpioToGPFSEL [pin] ;
    shift = gpioToShift  [pin] ;

    *(gpio + fSel) = (*(gpio + fSel) & ~(7 << shift)) | ((mode & 0x7) << shift) ;
  }
*/
}


/*
 * pinMode:
 *	Sets the mode of a pin to be input, output or PWM output
 *********************************************************************************
 */
void pinMode (int pin, int mode)
{
	struct wiringPiNodeStruct *node = wiringPiNodes ;

	setupCheck ("pinMode") ;

	if (wiringPiDebug)
		printf("PinMode: pin:%d,mode:%d\n", pin, mode);

	if ((pin & PI_GPIO_MASK) == 0) {
		if (wiringPiMode == WPI_MODE_PINS) {
			pin = pinToGpio[pin];
		} else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return;

		if (-1 == pin) {
			printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", 
					__func__,  __LINE__, pin);
			return;
		}

		if (mode == INPUT) {
			orangepi_set_gpio_mode(pin, INPUT);
			return;
		} 
		else if (mode == OUTPUT) {
			orangepi_set_gpio_mode(pin, OUTPUT);
			return ;
		}
		else if (mode == PWM_OUTPUT) {
			orangepi_set_gpio_mode(pin, PWM_OUTPUT);
			return;
		}
		else
			return;
	} 
	else
	{
		if ((node = wiringPiFindNode (pin)) != NULL)
			node->pinMode(node, pin, mode);

		return ;
	}
}


/*
 * pullUpDownCtrl:
 *	Control the internal pull-up/down resistors on a GPIO pin.
 *********************************************************************************
 */

void pullUpDnControl (int pin, int pud)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  setupCheck ("pullUpDnControl") ;

  if ((pin & PI_GPIO_MASK) == 0)		// On-Board Pin
  {
    /**/ if (wiringPiMode == WPI_MODE_PINS)
      pin = pinToGpio [pin] ;
    else if (wiringPiMode == WPI_MODE_PHYS)
      pin = physToGpio [pin] ;
    else if (wiringPiMode != WPI_MODE_GPIO)
      return ;

	if (pud == PUD_OFF) {
		OrangePi_set_gpio_pullUpDnControl(pin, PUD_OFF);
	}
	else if (pud == PUD_UP){
		OrangePi_set_gpio_pullUpDnControl(pin, PUD_UP);
	}
	else if (pud == PUD_DOWN){
		OrangePi_set_gpio_pullUpDnControl(pin, PUD_DOWN);
	}
  }
  else						// Extension module
  {
    if ((node = wiringPiFindNode (pin)) != NULL)
      node->pullUpDnControl (node, pin, pud) ;
    return ;
  }
}


/*
 * digitalRead:
 *	Read the value of a given Pin, returning HIGH or LOW
 *********************************************************************************
 */
int digitalRead (int pin)
{
	char c ;
	int ret;
	struct wiringPiNodeStruct *node = wiringPiNodes ;

	if ((pin & PI_GPIO_MASK) == 0)
	{
		if (wiringPiMode == WPI_MODE_GPIO_SYS)	// Sys mode
		{
			if (sysFds [pin] == -1)
				return LOW ;

			ret = lseek(sysFds [pin], 0L, SEEK_SET) ;
			ret = read(sysFds [pin], &c, 1);

			if (ret < 0)
				return -1;
			
			return (c == '0') ? LOW : HIGH ;
		} 
		else if (wiringPiMode == WPI_MODE_PINS)
			pin = pinToGpio[pin];
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return -1;

		if (pin == -1)
		{
			printf("[%s %d]Pin %d is invalid, please check it over!\n", __func__, __LINE__, pin);
			return LOW;
		}

		return orangepi_digitalRead(pin);
	}
	else 
	{
		if ((node = wiringPiFindNode (pin)) == NULL)
			return LOW ;
		
		return node->digitalRead (node, pin) ;
	}
}


/*
 * digitalRead8:
 *	Read 8-bits (a byte) from given start pin.
 *********************************************************************************

unsigned int digitalRead8 (int pin)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  if ((pin & PI_GPIO_MASK) == 0)		// On-Board Pin
    return 0 ;
  else
  {
    if ((node = wiringPiFindNode (pin)) == NULL)
      return LOW ;
    return node->digitalRead8 (node, pin) ;
  }
}
 */


/*
 * digitalWrite:
 *	Set an output bit
 *********************************************************************************
 */
void digitalWrite (int pin, int value)
{
	struct wiringPiNodeStruct *node = wiringPiNodes ;
	int ret;

	if ((pin & PI_GPIO_MASK) == 0) 
	{
		if (wiringPiMode == WPI_MODE_GPIO_SYS)
		{
			if (sysFds [pin] != -1) {
				if (value == LOW)
				{
					ret = write (sysFds [pin], "0\n", 2);
					if (ret < 0)
						return;
				}
				else
				{
					ret = write (sysFds [pin], "1\n", 2);
					if (ret < 0)
						return;
				}
			}
			return ;
		} 
		else if (wiringPiMode == WPI_MODE_PINS) 
		{
			pin = pinToGpio[pin];
		}
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else 
			return;

		if(-1 == pin)
		{
			printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", __func__,  __LINE__, pin);
			printf("[%s:L%d] the mode is: %d, please check it over!\n", __func__,  __LINE__, wiringPiMode);

			return;
		}

		orangepi_digitalWrite(pin, value);
	} 
	else 
	{
		if ((node = wiringPiFindNode(pin)) != NULL)
			node->digitalWrite(node, pin, value);
	}

	return;
}

/*
 * digitalWrite8:
 *	Set an output 8-bit byte on the device from the given pin number
 *********************************************************************************

void digitalWrite8 (int pin, int value)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  if ((pin & PI_GPIO_MASK) == 0)		// On-Board Pin
    return ;
  else
  {
    if ((node = wiringPiFindNode (pin)) != NULL)
      node->digitalWrite8 (node, pin, value) ;
  }
}
 */

/*
 * pwmWrite:
 *	Set an output PWM value
 *********************************************************************************
 */

void pwmWrite(int pin, int value)
{
	struct wiringPiNodeStruct *node = wiringPiNodes;

	if (pinToGpio == 0 || physToGpio == 0) {
		printf("please call wiringPiSetup first.\n");
		return;
	}

	//if (pwmmode == 1) {
	//	sunxi_pwm_set_mode(1);
	//} else {
	//	sunxi_pwm_set_mode(0);
	//}

	// On-Board Pin needto fix me Jim
	if (pin < MAX_PIN_NUM) {
		if (wiringPiMode == WPI_MODE_PINS)
			pin = pinToGpio [pin];
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return;

		if (-1 == pin) {
			printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", __func__, __LINE__, pin);
			return;
		}
		orangepi_pwm_set_act(pin,value);
	} else {
		printf("not on board :%s,%d\n", __func__, __LINE__);
		if ((node = wiringPiFindNode(pin)) != NULL) {
			if (wiringPiDebug)
				printf("Jim find node%s,%d\n", __func__, __LINE__);
			node->digitalWrite(node, pin, value);
		}
	}

	if (wiringPiDebug)
		printf("this fun is ok now %s,%d\n", __func__, __LINE__);
 
	return;
}

/*
 * analogRead:
 *	Read the analog value of a given Pin. 
 *	There is no on-board Pi analog hardware,
 *	so this needs to go to a new node.
 *********************************************************************************
 */

int analogRead (int pin)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  if ((node = wiringPiFindNode (pin)) == NULL)
    return 0 ;
  else
    return node->analogRead (node, pin) ;
}


/*
 * analogWrite:
 *	Write the analog value to the given Pin. 
 *	There is no on-board Pi analog hardware,
 *	so this needs to go to a new node.
 *********************************************************************************
 */

void analogWrite (int pin, int value)
{
  struct wiringPiNodeStruct *node = wiringPiNodes ;

  if ((node = wiringPiFindNode (pin)) == NULL)
    return ;

  node->analogWrite (node, pin, value) ;
}


/*
 * pwmToneWrite:
 *	Pi Specific.
 *      Output the given frequency on the Pi's PWM pin
 *********************************************************************************
 */

void pwmToneWrite (int pin, int freq)
{
	if ((pin & PI_GPIO_MASK) == 0) {
		if (wiringPiMode == WPI_MODE_PINS)
			pin = pinToGpio[pin];
		else if (wiringPiMode == WPI_MODE_PHYS)
			pin = physToGpio[pin];
		else if (wiringPiMode != WPI_MODE_GPIO)
			return;
	}

	if (-1 == pin) {
		printf("[%s:L%d] the pin:%d is invaild,please check it over!\n", __func__,  __LINE__, pin);
		return;
	}

	orangepi_pwm_set_tone(pin,freq);

	return;
}


/*
 * digitalWriteByte:
 * digitalReadByte:
 *	Pi Specific
 *	Write an 8-bit byte to the first 8 GPIO pins - try to do it as
 *	fast as possible.
 *	However it still needs 2 operations to set the bits, so any external
 *	hardware must not rely on seeing a change as there will be a change 
 *	to set the outputs bits to zero, then another change to set the 1's
 *	Reading is just bit fiddling.
 *	These are wiringPi pin numbers 0..7, or BCM_GPIO pin numbers
 *	17, 18, 22, 23, 24, 24, 4 on a Pi v1 rev 0-3
 *	17, 18, 27, 23, 24, 24, 4 on a Pi v1 rev 3 onwards or B+, 2, 3, zero
 *********************************************************************************
 */

void digitalWriteByte (const int value)
{
	int mask = 1 ;
	int pin ;

	for (pin = 0 ; pin < 8 ; ++pin) {
		digitalWrite (pin, (value >> pin) & mask) ;
	}
	
	return ;
}

unsigned int digitalReadByte (void)
{
	int pin, x ;
	uint32_t data = 0 ;

	for (pin = 7 ; pin >= 0 ; --pin){
		x = digitalRead(pin);
		
		data = (data << 1) | x ;
	}
	
	return data ;
}

/*
 * digitalWriteByte2:
 * digitalReadByte2:
 *	Pi Specific
 *	Write an 8-bit byte to the second set of 8 GPIO pins. This is marginally
 *	faster than the first lot as these are consecutive BCM_GPIO pin numbers.
 *	However they overlap with the original read/write bytes.
 *********************************************************************************
 */

void digitalWriteByte2 (const int value)
{
  register int mask = 1 ;
  register int pin ;

  /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS)
  {
    for (pin = 20 ; pin < 28 ; ++pin)
    {
      digitalWrite (pin, value & mask) ;
      mask <<= 1 ;
    }
    return ;
  }
  else
  {
    *(gpio + gpioToGPCLR [0]) = (~value & 0xFF) << 20 ; // 0x0FF00000; ILJ > CHANGE: Old causes glitch
    *(gpio + gpioToGPSET [0]) = ( value & 0xFF) << 20 ;
  }
}

unsigned int digitalReadByte2 (void)
{
  int pin, x ;
  uint32_t data = 0 ;

  /**/ if (wiringPiMode == WPI_MODE_GPIO_SYS)
  {
    for (pin = 20 ; pin < 28 ; ++pin)
    {
      x = digitalRead (pin) ;
      data = (data << 1) | x ;
    }
  }
  else 
    data = ((*(gpio + gpioToGPLEV [0])) >> 20) & 0xFF ; // First bank for these pins

  return data ;
}


/*
 * waitForInterrupt:
 *	Pi Specific.
 *	Wait for Interrupt on a GPIO pin.
 *	This is actually done via the /sys/class/gpio interface regardless of
 *	the wiringPi access mode in-use. Maybe sometime it might get a better
 *	way for a bit more efficiency.
 *********************************************************************************
 */

int waitForInterrupt (int pin, int mS)
{
  int fd, x ;
  uint8_t c ;
  struct pollfd polls ;
  int ret;

  /**/ if (wiringPiMode == WPI_MODE_PINS)
    pin = pinToGpio [pin] ;
  else if (wiringPiMode == WPI_MODE_PHYS)
    pin = physToGpio [pin] ;

  if ((fd = sysFds [pin]) == -1)
    return -2 ;

// Setup poll structure

  polls.fd     = fd ;
  polls.events = POLLPRI | POLLERR ;

// Wait for it ...

  x = poll (&polls, 1, mS) ;

// If no error, do a dummy read to clear the interrupt
//	A one character read appars to be enough.

  if (x > 0)
  {
    lseek (fd, 0, SEEK_SET) ;	// Rewind
    ret = read (fd, &c, 1) ;	// Read & clear
   if (ret < 0)
  	return -1;
  }

  return x ;
}


/*
 * interruptHandler:
 *	This is a thread and gets started to wait for the interrupt we're
 *	hoping to catch. It will call the user-function when the interrupt
 *	fires.
 *********************************************************************************
 */

static void *interruptHandler (UNU void *arg)
{
  int myPin ;

  (void)piHiPri (55) ;	// Only effective if we run as root

  myPin   = pinPass ;
  pinPass = -1 ;

  for (;;)
    if (waitForInterrupt (myPin, -1) > 0)
      isrFunctions [myPin] () ;

  return NULL ;
}


/*
 * wiringPiISR:
 *	Pi Specific.
 *	Take the details and create an interrupt handler that will do a call-
 *	back to the user supplied function.
 *********************************************************************************
 */

int wiringPiISR (int pin, int mode, void (*function)(void))
{
  pthread_t threadId ;
  const char *modeS ;
  char fName   [64] ;
  char  pinS [8] ;
  pid_t pid ;
  int   count, i ;
  char  c ;
  int   bcmGpioPin ;
  int ret;

  if ((pin < 0) || (pin > 63))
    return wiringPiFailure (WPI_FATAL, "wiringPiISR: pin must be 0-63 (%d)\n", pin) ;

  /**/ if (wiringPiMode == WPI_MODE_UNINITIALISED)
    return wiringPiFailure (WPI_FATAL, "wiringPiISR: wiringPi has not been initialised. Unable to continue.\n") ;
  else if (wiringPiMode == WPI_MODE_PINS)
    bcmGpioPin = pinToGpio [pin] ;
  else if (wiringPiMode == WPI_MODE_PHYS)
    bcmGpioPin = physToGpio [pin] ;
  else
    bcmGpioPin = pin ;

// Now export the pin and set the right edge
//	We're going to use the gpio program to do this, so it assumes
//	a full installation of wiringPi. It's a bit 'clunky', but it
//	is a way that will work when we're running in "Sys" mode, as
//	a non-root user. (without sudo)

  if (mode != INT_EDGE_SETUP)
  {
    /**/ if (mode == INT_EDGE_FALLING)
      modeS = "falling" ;
    else if (mode == INT_EDGE_RISING)
      modeS = "rising" ;
    else
      modeS = "both" ;

    sprintf (pinS, "%d", bcmGpioPin);

    if ((pid = fork ()) < 0)	// Fail
      return wiringPiFailure (WPI_FATAL, "wiringPiISR: fork failed: %s\n", strerror (errno)) ;

    if (pid == 0)	// Child, exec
    {
      /**/ if (access ("/usr/local/bin/gpio", X_OK) == 0)
      {
	execl ("/usr/local/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
      }
      else if (access ("/usr/bin/gpio", X_OK) == 0)
      {
	execl ("/usr/bin/gpio", "gpio", "edge", pinS, modeS, (char *)NULL) ;
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: execl failed: %s\n", strerror (errno)) ;
      }
      else
	return wiringPiFailure (WPI_FATAL, "wiringPiISR: Can't find gpio program\n") ;
    }
    else		// Parent, wait
      wait (NULL) ;
  }

// Now pre-open the /sys/class node - but it may already be open if
//	we are in Sys mode...

  if (sysFds [bcmGpioPin] == -1)
  {
    sprintf (fName, "/sys/class/gpio/gpio%d/value", bcmGpioPin) ;
    if ((sysFds [bcmGpioPin] = open (fName, O_RDWR)) < 0)
      return wiringPiFailure (WPI_FATAL, "wiringPiISR: unable to open %s: %s\n", fName, strerror (errno)) ;
  }

// Clear any initial pending interrupt

  ioctl (sysFds [bcmGpioPin], FIONREAD, &count) ;
  for (i = 0 ; i < count ; ++i){
    ret = read (sysFds [bcmGpioPin], &c, 1) ;
	if (ret < 0)
		return -1;
  }

  isrFunctions [pin] = function ;

  pthread_mutex_lock (&pinMutex) ;
    pinPass = pin ;
    pthread_create (&threadId, NULL, interruptHandler, NULL) ;
    while (pinPass != -1)
      delay (1) ;
  pthread_mutex_unlock (&pinMutex) ;

  return 0 ;
}


/*
 * initialiseEpoch:
 *	Initialise our start-of-time variable to be the current unix
 *	time in milliseconds and microseconds.
 *********************************************************************************
 */

static void initialiseEpoch (void)
{
#ifdef	OLD_WAY
  struct timeval tv ;

  gettimeofday (&tv, NULL) ;
  epochMilli = (uint64_t)tv.tv_sec * (uint64_t)1000    + (uint64_t)(tv.tv_usec / 1000) ;
  epochMicro = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)(tv.tv_usec) ;
#else
  struct timespec ts ;

  clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ;
  epochMilli = (uint64_t)ts.tv_sec * (uint64_t)1000    + (uint64_t)(ts.tv_nsec / 1000000L) ;
  epochMicro = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec /    1000L) ;
#endif
}


/*
 * delay:
 *	Wait for some number of milliseconds
 *********************************************************************************
 */

void delay (unsigned int howLong)
{
  struct timespec sleeper, dummy ;

  sleeper.tv_sec  = (time_t)(howLong / 1000) ;
  sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;

  nanosleep (&sleeper, &dummy) ;
}


/*
 * delayMicroseconds:
 *	This is somewhat intersting. It seems that on the Pi, a single call
 *	to nanosleep takes some 80 to 130 microseconds anyway, so while
 *	obeying the standards (may take longer), it's not always what we
 *	want!
 *
 *	So what I'll do now is if the delay is less than 100uS we'll do it
 *	in a hard loop, watching a built-in counter on the ARM chip. This is
 *	somewhat sub-optimal in that it uses 100% CPU, something not an issue
 *	in a microcontroller, but under a multi-tasking, multi-user OS, it's
 *	wastefull, however we've no real choice )-:
 *
 *      Plan B: It seems all might not be well with that plan, so changing it
 *      to use gettimeofday () and poll on that instead...
 *********************************************************************************
 */

void delayMicrosecondsHard (unsigned int howLong)
{
  struct timeval tNow, tLong, tEnd ;

  gettimeofday (&tNow, NULL) ;
  tLong.tv_sec  = howLong / 1000000 ;
  tLong.tv_usec = howLong % 1000000 ;
  timeradd (&tNow, &tLong, &tEnd) ;

  while (timercmp (&tNow, &tEnd, <))
    gettimeofday (&tNow, NULL) ;
}

void delayMicroseconds (unsigned int howLong)
{
  struct timespec sleeper ;
  unsigned int uSecs = howLong % 1000000 ;
  unsigned int wSecs = howLong / 1000000 ;

  /**/ if (howLong ==   0)
    return ;
  else if (howLong  < 100)
    delayMicrosecondsHard (howLong) ;
  else
  {
    sleeper.tv_sec  = wSecs ;
    sleeper.tv_nsec = (long)(uSecs * 1000L) ;
    nanosleep (&sleeper, NULL) ;
  }
}


/*
 * millis:
 *	Return a number of milliseconds as an unsigned int.
 *	Wraps at 49 days.
 *********************************************************************************
 */

unsigned int millis (void)
{
  uint64_t now ;

#ifdef	OLD_WAY
  struct timeval tv ;

  gettimeofday (&tv, NULL) ;
  now  = (uint64_t)tv.tv_sec * (uint64_t)1000 + (uint64_t)(tv.tv_usec / 1000) ;

#else
  struct  timespec ts ;

  clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ;
  now  = (uint64_t)ts.tv_sec * (uint64_t)1000 + (uint64_t)(ts.tv_nsec / 1000000L) ;
#endif

  return (uint32_t)(now - epochMilli) ;
}


/*
 * micros:
 *	Return a number of microseconds as an unsigned int.
 *	Wraps after 71 minutes.
 *********************************************************************************
 */

unsigned int micros (void)
{
  uint64_t now ;
#ifdef	OLD_WAY
  struct timeval tv ;

  gettimeofday (&tv, NULL) ;
  now  = (uint64_t)tv.tv_sec * (uint64_t)1000000 + (uint64_t)tv.tv_usec ;
#else
  struct  timespec ts ;

  clock_gettime (CLOCK_MONOTONIC_RAW, &ts) ;
  now  = (uint64_t)ts.tv_sec * (uint64_t)1000000 + (uint64_t)(ts.tv_nsec / 1000) ;
#endif


  return (uint32_t)(now - epochMicro) ;
}

/*
 * wiringPiVersion:
 *	Return our current version number
 *********************************************************************************
 */

void wiringPiVersion (int *major, int *minor)
{
  *major = VERSION_MAJOR ;
  *minor = VERSION_MINOR ;
}

void set_soc_info(void)
{
	switch (OrangePiModel)
	{
		case PI_MODEL_3:
		case PI_MODEL_LTIE_2:
		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:
			sunxi_gpio_info_t.gpio_base_addr = H6_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.r_gpio_base_addr = H6_R_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.gpio_base_offset = 0x0;
			sunxi_gpio_info_t.r_gpio_base_offset = 0x0;
			sunxi_gpio_info_t.pwm_base_addr = H6_PWM_BASE;
			sunxi_gpio_info_t.gpio_bank_offset = 0x24;
			sunxi_gpio_info_t.pull_offset = 0x1c;
			sunxi_gpio_info_t.gpio_cfg_mask = 0x7;
			break;
		case PI_MODEL_4A:
			sunxi_gpio_info_t.gpio_base_addr = A527_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.r_gpio_base_addr = H6_R_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.gpio_base_offset = 0x0;
			sunxi_gpio_info_t.r_gpio_base_offset = 0x0;
			sunxi_gpio_info_t.gpio_bank_offset = 0x30;
			sunxi_gpio_info_t.pull_offset = 0x24;
			sunxi_gpio_info_t.gpio_cfg_mask = 0xf;
			break;
		case PI_MODEL_ZERO:
		case PI_MODEL_ZERO_PLUS_2:
		case PI_MODEL_WIN:
		case PI_MODEL_PRIME:
		case PI_MODEL_PC_2:
		case PI_MODEL_ZERO_PLUS:
		case PI_MODEL_H3:
			sunxi_gpio_info_t.gpio_base_addr = H3_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.r_gpio_base_addr = H3_R_GPIO_BASE_ADDR;
			sunxi_gpio_info_t.gpio_base_offset = 0x800;
			sunxi_gpio_info_t.r_gpio_base_offset = 0xc00;
			sunxi_gpio_info_t.pwm_base_addr = H3_PWM_BASE;
			sunxi_gpio_info_t.gpio_bank_offset = 0x24;
			sunxi_gpio_info_t.pull_offset = 0x1c;
			sunxi_gpio_info_t.gpio_cfg_mask = 0x7;
			break;
		default:
			break;
	}

	switch (OrangePiModel)
	{
		case PI_MODEL_3:
		case PI_MODEL_LTIE_2:
		case PI_MODEL_ZERO:
		case PI_MODEL_ZERO_PLUS_2:
		case PI_MODEL_WIN:
		case PI_MODEL_PRIME:
		case PI_MODEL_PC_2:
		case PI_MODEL_ZERO_PLUS:
		case PI_MODEL_H3:
			sunxi_gpio_info_t.pwm_ctrl = SUNXI_V1_PWM_CTRL_REG;
			sunxi_gpio_info_t.pwm_period = SUNXI_V1_PWM_CH0_PERIOD;
			sunxi_gpio_info_t.pwm_clk = SUNXI_V1_PWM_CTRL_REG;
			sunxi_gpio_info_t.pwm_en = SUNXI_V1_PWM_CTRL_REG;
			sunxi_gpio_info_t.pwm_type = SUNXI_V1_PWM_TYPE;
			sunxi_gpio_info_t.pwm_bit_en = SUNXI_V1_PWM_CH0_EN; 	// SUNXI_PWM_CH0_EN
			sunxi_gpio_info_t.pwm_bit_act = SUNXI_V1_PWM_CH0_ACT_STA;	// SUNXI_PWM_CH0_ACT_STA
			sunxi_gpio_info_t.pwm_bit_sclk = SUNXI_V1_PWM_SCLK_CH0_GATING;	// SUNXI_PWM_SCLK_CH0_GATING
			sunxi_gpio_info_t.pwm_bit_mode = SUNXI_V1_PWM_CH0_MS_MODE;	// SUNXI_PWM_CH0_MS_MODE
			sunxi_gpio_info_t.pwm_bit_pulse = SUNXI_V1_PWM_CH0_PUL_START;	// SUNXI_PWM_CH0_PUL_START
			break;
		case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO_2_W:
			sunxi_gpio_info_t.pwm_en = SUNXI_V2_PWM_EN_REG;
			sunxi_gpio_info_t.pwm_type = SUNXI_V2_PWM_TYPE;	// H616
			sunxi_gpio_info_t.pwm_bit_act = SUNXI_V2_PWM_ACT_STA;
			sunxi_gpio_info_t.pwm_bit_sclk = SUNXI_V2_PWM_SCLK_GATING;
			sunxi_gpio_info_t.pwm_bit_mode = SUNXI_V2_PWM_MS_MODE;
			sunxi_gpio_info_t.pwm_bit_pulse = SUNXI_V2_PWM_PUL_START;
			break;
		default:
			break;
	}

}

/*
 * wiringPiSetup:
 *	Must be called once at the start of your program execution.
 *
 * Default setup: Initialises the system into wiringPi Pin mode and uses the
 *	memory mapped hardware directly.
 *
 * Changed now to revert to "gpio" mode if we're running on a Compute Module.
 *********************************************************************************
 */

int wiringPiSetup (void)
{
	int fd;

	// It's actually a fatal error to call any of the wiringPiSetup routines more than once,
	//	(you run out of file handles!) but I'm fed-up with the useless twats who email
	//	me bleating that there is a bug in my code, so screw-em.

	if (wiringPiSetuped)
		return 0 ;

	wiringPiSetuped = TRUE ;

	if (getenv (ENV_DEBUG) != NULL)
		wiringPiDebug = TRUE ;

	if (getenv (ENV_CODES) != NULL)
		wiringPiReturnCodes = TRUE ;

	if (wiringPiDebug)
	printf ("wiringPi: wiringPiSetup called\n") ;

	piBoardId (&OrangePiModel) ;

	wiringPiMode = WPI_MODE_PINS ;

	switch (OrangePiModel)
	{
		case PI_MODEL_3:
			pinToGpio =  pinToGpio_3;
			physToGpio = physToGpio_3;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_3;
			break;
		case PI_MODEL_LTIE_2:
			pinToGpio =  pinToGpio_LITE_2;
			physToGpio = physToGpio_LITE_2;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_LITE_2;
			break;
		case PI_MODEL_ZERO:
			pinToGpio =  pinToGpio_ZERO;
			physToGpio = physToGpio_ZERO;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_ZERO;
			break;
		case PI_MODEL_ZERO_PLUS_2:
			pinToGpio =  pinToGpio_ZERO_PLUS_2;
			physToGpio = physToGpio_ZERO_PLUS_2;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_ZERO_PLUS_2;
			break;
		case PI_MODEL_WIN:
			pinToGpio =  pinToGpio_WIN;
			physToGpio = physToGpio_WIN;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_WIN;
			break;
		case PI_MODEL_PRIME:
			pinToGpio =  pinToGpio_PRIME;
			physToGpio = physToGpio_PRIME;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_PRIME;
			break;
		case PI_MODEL_PC_2:
			pinToGpio =  pinToGpio_PC_2;
			physToGpio = physToGpio_PC_2;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_PC_2;
			break;
		case PI_MODEL_ZERO_PLUS:
			pinToGpio =  pinToGpio_ZERO_PLUS;
			physToGpio = physToGpio_ZERO_PLUS;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_ZERO_PLUS;
			break;
		case PI_MODEL_ZERO_2:
			pinToGpio =  pinToGpio_ZERO_2;
			physToGpio = physToGpio_ZERO_2;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_ZERO_2;
			break;
		case PI_MODEL_ZERO_2_W:
			pinToGpio =  pinToGpio_ZERO_2_W;
			physToGpio = physToGpio_ZERO_2_W;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_ZERO_2_W;
			break;
		case PI_MODEL_4A:
			pinToGpio =  pinToGpio_4A;
			physToGpio = physToGpio_4A;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_4A;
			break;
		case PI_MODEL_800:
			pinToGpio =  pinToGpio_800;
			physToGpio = physToGpio_800;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_800;
			break;
		case PI_MODEL_4:
			pinToGpio =  pinToGpio_4;
			physToGpio = physToGpio_4;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_4;
			break;
		case PI_MODEL_4_LTS:
			pinToGpio =  pinToGpio_4_LTS;
			physToGpio = physToGpio_4_LTS;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_4_LTS;
			break;
		case PI_MODEL_RK3399:
			pinToGpio =  pinToGpio_RK3399;
			physToGpio = physToGpio_RK3399;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_RK3399;
			break;
		case PI_MODEL_R1_PLUS:
			pinToGpio =  pinToGpio_R1_PLUS;
			physToGpio = physToGpio_R1_PLUS;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_R1_PLUS;
			break;
		case PI_MODEL_H3:
			pinToGpio =  pinToGpio_H3;
			physToGpio = physToGpio_H3;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_H3;
			break;
		case PI_MODEL_5:
			pinToGpio =  pinToGpio_5;
			physToGpio = physToGpio_5;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5;
			break;
		case PI_MODEL_5B:
			pinToGpio =  pinToGpio_5B;
			physToGpio = physToGpio_5B;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5B;
			break;
		case PI_MODEL_CM5:
			pinToGpio =  pinToGpio_CM5;
			physToGpio = physToGpio_CM5;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_CM5;
			break;
		case PI_MODEL_CM5_TABLET:
			pinToGpio =  pinToGpio_CM5_TABLET;
			physToGpio = physToGpio_CM5_TABLET;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_CM5_TABLET;
			break;
		case PI_MODEL_5_PRO:
			pinToGpio =  pinToGpio_5PRO;
			physToGpio = physToGpio_5PRO;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5PRO;
			break;
		case PI_MODEL_5_MAX:
			pinToGpio =  pinToGpio_5MAX;
			physToGpio = physToGpio_5MAX;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5MAX;
			break;
		case PI_MODEL_5_ULTRA:
			pinToGpio =  pinToGpio_5ULTRA;
			physToGpio = physToGpio_5ULTRA;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5ULTRA;
			break;
		case PI_MODEL_5_PLUS:
			pinToGpio =  pinToGpio_5PLUS;
			physToGpio = physToGpio_5PLUS;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_5PLUS;
			break;
		case PI_MODEL_AI_MAX:
			pinToGpio =  pinToGpio_AIMAX;
			physToGpio = physToGpio_AIMAX;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_AIMAX;
			break;
		case PI_MODEL_900:
			pinToGpio =  pinToGpio_900;
			physToGpio = physToGpio_900;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_900;
			break;
		case PI_MODEL_CM4:
			pinToGpio =  pinToGpio_CM4;
			physToGpio = physToGpio_CM4;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_CM4;
			break;
		case PI_MODEL_3B:
			pinToGpio =  pinToGpio_3B;
			physToGpio = physToGpio_3B;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_3B;
			break;
		case PI_MODEL_3_PLUS:
			pinToGpio = pinToGpio_3PLUS;
			physToGpio = physToGpio_3PLUS;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_3PLUS;
			break;
		case PI_MODEL_AI_PRO:
			pinToGpio =  pinToGpio_AIPRO;
			physToGpio = physToGpio_AIPRO;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_AIPRO;
			break;
		case PI_MODEL_RV:
			pinToGpio = pinToGpio_RV;
			physToGpio = physToGpio_RV;
			ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_RV;
			break;
		default:
			printf ("Oops - unable to determine board type... model: %d\n", OrangePiModel);
			break ;
	}

	set_soc_info();

	// Open the master /dev/ memory control device
	// Device strategy: December 2016:
	//	Try /dev/mem. If that fails, then 
	//	try /dev/gpiomem. If that fails then game over.
	if ((fd = open ("/dev/mem", O_RDWR | O_SYNC | O_CLOEXEC)) < 0){
		if ((fd = open ("/dev/gpiomem", O_RDWR | O_SYNC | O_CLOEXEC) ) >= 0){	// We're using gpiomem
			piGpioBase   = 0 ;
			usingGpioMem = TRUE ;
		}
		else
			return wiringPiFailure (WPI_ALMOST, "wiringPiSetup: Unable to open /dev/mem or /dev/gpiomem: %s.\n"
			"  Aborting your program because if it can not access the GPIO\n"
			"  hardware then it most certianly won't work\n"
			"  Try running with sudo?\n", strerror (errno)) ;
	}

	switch (OrangePiModel)
	{
		case PI_MODEL_3: case PI_MODEL_LTIE_2: case PI_MODEL_ZERO_2:
		case PI_MODEL_ZERO: case PI_MODEL_ZERO_PLUS_2: case PI_MODEL_WIN:
		case PI_MODEL_PRIME: case PI_MODEL_PC_2: case PI_MODEL_ZERO_PLUS:
		case PI_MODEL_H3: case PI_MODEL_ZERO_2_W: case PI_MODEL_4A:
	
			sunxi_gpio_info_t.pwm = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, sunxi_gpio_info_t.pwm_base_addr);
			if ((int32_t)(unsigned long)sunxi_gpio_info_t.pwm == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (PWM) failed: %s\n", strerror(errno));

			sunxi_gpio_info_t.gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, sunxi_gpio_info_t.gpio_base_addr);
			if ((int32_t)(unsigned long)sunxi_gpio_info_t.gpio == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO) failed: %s\n", strerror(errno));

			sunxi_gpio_info_t.r_gpio = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, sunxi_gpio_info_t.r_gpio_base_addr);
			if ((int32_t)(unsigned long)sunxi_gpio_info_t.r_gpio == -1)
				return wiringPiFailure(WPI_ALMOST,  "wiringPiSetup: mmap (GPIO) failed: %s\n", strerror(errno));

			break;

		case PI_MODEL_R1_PLUS:

			rk3328_soc_info_t.cru_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3328_CRU_BASE);
			if ((int32_t)(unsigned long)rk3328_soc_info_t.cru_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (CRU_BASE) failed: %s\n", strerror(errno));

			rk3328_soc_info_t.grf_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3328_GRF_BASE);
			if ((int32_t)(unsigned long)rk3328_soc_info_t.grf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GRF_BASE) failed: %s\n", strerror(errno));

			rk3328_soc_info_t.gpio2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3328_GPIO2_BASE);
			if ((int32_t)(unsigned long)rk3328_soc_info_t.gpio2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO2_BASE) failed: %s\n", strerror(errno));

			rk3328_soc_info_t.gpio3_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3328_GPIO3_BASE);
			if ((int32_t)(unsigned long)rk3328_soc_info_t.gpio3_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO3_BASE) failed: %s\n", strerror(errno));

			break;

		case PI_MODEL_RK3399: case PI_MODEL_4: case PI_MODEL_4_LTS: case PI_MODEL_800:

			rk3399_soc_info_t.gpio2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_GPIO2_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.gpio2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO2_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.cru_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_CRU_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.cru_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (CRU_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.pmucru_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_PMUCRU_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.pmucru_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (PMUCRU_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.grf_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_GRF_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.grf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GRF_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.pmugrf_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_PMUGRF_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.pmugrf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (PMUGRF_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.gpio1_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_GPIO1_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.grf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO1_BASE) failed: %s\n", strerror(errno));

			rk3399_soc_info_t.gpio4_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3399_GPIO4_BASE);
			if ((int32_t)(unsigned long)rk3399_soc_info_t.gpio4_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (GPIO4_BASE) failed: %s\n", strerror(errno));

			break;

		case PI_MODEL_5: case PI_MODEL_5B: case PI_MODEL_5_PRO: case PI_MODEL_5_MAX: case PI_MODEL_5_PLUS: case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_AI_MAX:

			/* GPIO Register */
			rk3588_soc_info_t.gpio0_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_GPIO0_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.gpio0_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_GPIO0_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.gpio1_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_GPIO1_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.gpio1_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_GPIO1_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.gpio2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_GPIO2_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.gpio2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_GPIO2_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.gpio3_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_GPIO3_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.gpio3_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_GPIO3_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.gpio4_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_GPIO4_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.gpio4_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_GPIO4_BASE) failed: %s\n", strerror(errno));


			rk3588_soc_info_t.pmu1_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PMU1_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu1_ioc_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PMU1_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pmu2_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PMU2_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu2_ioc_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PMU2_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.bus_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_BUS_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.bus_ioc_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_BUS_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.cur_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_CRU_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.cur_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_CRU_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pmu1cur_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PMU1CRU_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu1cur_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PMU1CRU_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.vccio1_4_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_VCCIO1_4_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu1cur_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_VCCIO1_4_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.vccio3_5_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_VCCIO3_5_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu1cur_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_VCCIO3_5_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.vccio6_ioc_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_VCCIO6_IOC_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pmu1cur_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_VCCIO6_IOC_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pwm0_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PWM0_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pwm0_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PWM0_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pwm1_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PWM1_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pwm1_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PWM1_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pwm2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PWM2_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pwm2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PWM2_BASE) failed: %s\n", strerror(errno));

			rk3588_soc_info_t.pwm3_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3588_PWM3_BASE);
			if ((int32_t)(unsigned long)rk3588_soc_info_t.pwm3_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3588_PWM3_BASE) failed: %s\n", strerror(errno));

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			/* GPIO Register */
			rk3566_soc_info_t.gpio0_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_GPIO0_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.gpio0_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_GPIO0_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.gpio1_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_GPIO1_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.gpio1_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_GPIO1_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.gpio2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_GPIO2_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.gpio2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_GPIO2_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.gpio3_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_GPIO3_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.gpio3_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_GPIO3_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.gpio4_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_GPIO4_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.gpio4_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_GPIO4_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.pmu_grf_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_PMU_GRF_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.pmu_grf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_PMU_GRF_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.sys_grf_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_SYS_GRF_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.sys_grf_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_SYS_GRF_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.cru_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_CRU_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.cru_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_CRU_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.pmu_cru_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_PMU_CRU_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.pmu_cru_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_PMU_CRU_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.pwm2_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_PWM2_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.pwm2_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_PWM2_BASE) failed: %s\n", strerror(errno));

			rk3566_soc_info_t.pwm3_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, RK3566_PWM3_BASE);
			if ((int32_t)(unsigned long)rk3566_soc_info_t.pwm3_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (RK3566_PWM3_BASE) failed: %s\n", strerror(errno));

			if(0x20 & readR(RK3566_PMU_GRF_BASE + 0x144)) {
				pinToGpio =  pinToGpio_CM4;
				physToGpio = physToGpio_CM4;
				ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_CM4;
			} else {
				pinToGpio =  pinToGpio_3B;
				physToGpio = physToGpio_3B;
				ORANGEPI_PIN_MASK = ORANGEPI_PIN_MASK_3B;
			}

			break;

		case PI_MODEL_3_PLUS:

			/* GPIO Register */
			s905d3_gpio_info_t.gpio_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, S905D3_GPIO_BASE);
			if ((int32_t)(unsigned long)s905d3_gpio_info_t.gpio_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (S905D3_GPIO_BASE) failed: %s\n", strerror(errno));

			s905d3_gpio_info_t.gpio_ao_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, S905D3_GPIO_AO_BASE);
			if ((int32_t)(unsigned long)s905d3_gpio_info_t.gpio_ao_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (S905D3_AO_GPIO_BASE) failed: %s\n", strerror(errno));

			/* PWM Register */
			s905d3_gpio_info_t.gpio_pwm_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, S905D3_GPIO_PWM_BASE);
			if ((int32_t)(unsigned long)s905d3_gpio_info_t.gpio_pwm_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (S905D3_GPIO_PWM_BASE) failed: %s\n", strerror(errno));

			s905d3_gpio_info_t.gpio_pwm_ao_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, S905D3_GPIO_PWM_AO_BASE);
			if ((int32_t)(unsigned long)s905d3_gpio_info_t.gpio_pwm_ao_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (S905D3_GPIO_PWM_AO_BASE) failed: %s\n", strerror(errno));
			break;

		case PI_MODEL_AI_PRO:

			// IOMUX BASE
			a310b_gpio_info_t.iomux_base_group0 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP0 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group0 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP0) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group1 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP1 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group1 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP1) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group2 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP2 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group2 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP2) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group3 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP3 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group3 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP3) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group4 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP4 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group4 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP4) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group5 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP5 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group5 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP5) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.iomux_base_group7 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_IOMUX_BASE_GROUP7 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.iomux_base_group7 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_IOMUX_BASE_GROUP7) failed: %s\n", strerror(errno));

			// GPIO BASE
			a310b_gpio_info_t.gpio_base_group0 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP0 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group0 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP0) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group1 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP1 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group1 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP1) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group2 = mmap(0, MAP_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP2 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group2 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP2) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group3 = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP3 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group3 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP3) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group4 = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP4 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group4 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP4) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group5 = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP5 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group5 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP5) failed: %s\n", strerror(errno));

			a310b_gpio_info_t.gpio_base_group7 = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_GPIO_BASE_GROUP7 & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.gpio_base_group7 == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_GPIO_BASE_GROUP7) failed: %s\n", strerror(errno));

			// PWM BASE
			a310b_gpio_info_t.pwm_base = mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, A310B_PWM_BASE & ~MAP_MASK);
			if ((int32_t)(unsigned long)a310b_gpio_info_t.pwm_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (A310B_PMW_BASE) failed: %s\n", strerror(errno));

			break;

		case PI_MODEL_RV:

			jh7110_soc_info_t.sys_iomux_base = (uint32_t *)mmap(0, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, JH7110_SYS_IOMUX_BASE);
			if ((int32_t)(unsigned long)jh7110_soc_info_t.sys_iomux_base == -1)
				return wiringPiFailure(WPI_ALMOST, "wiringPiSetup: mmap (JH7110_SYS_IOMUX_BASE) failed: %s\n", strerror(errno));
			break;

		default:

			printf("model %d is error\n", OrangePiModel);
			break ;
	}

	initialiseEpoch () ;

	return 0 ;
}

/*
 * wiringPiSetupGpio:
 *	Must be called once at the start of your program execution.
 *
 * GPIO setup: Initialises the system into GPIO Pin mode and uses the
 *	memory mapped hardware directly.
 *********************************************************************************
 */

int wiringPiSetupGpio (void)
{
	(void)wiringPiSetup () ;

	if (wiringPiDebug)
		printf ("wiringPi: wiringPiSetupGpio called\n") ;

	wiringPiMode = WPI_MODE_GPIO ;

	return 0 ;
}


/*
 * wiringPiSetupPhys:
 *	Must be called once at the start of your program execution.
 *
 * Phys setup: Initialises the system into Physical Pin mode and uses the
 *	memory mapped hardware directly.
 *********************************************************************************
 */

int wiringPiSetupPhys (void)
{
  (void)wiringPiSetup () ;

  if (wiringPiDebug)
    printf ("wiringPi: wiringPiSetupPhys called\n") ;

  wiringPiMode = WPI_MODE_PHYS ;

  return 0 ;
}

/*
 * wiringPiSetupSys:
 *	Must be called once at the start of your program execution.
 *
 * Initialisation (again), however this time we are using the /sys/class/gpio
 *	interface to the GPIO systems - slightly slower, but always usable as
 *	a non-root user, assuming the devices are already exported and setup correctly.
 */

int wiringPiSetupSys (void)
{
	int pin ;
	int tmpGpio;
	char fName [128] ;

	if (wiringPiSysSetuped)
		return 0 ;

	wiringPiSysSetuped = TRUE ;

	if (getenv (ENV_DEBUG) != NULL)
		wiringPiDebug = TRUE ;

	if (getenv (ENV_CODES) != NULL)
		wiringPiReturnCodes = TRUE ;

	if (wiringPiDebug)
		printf ("wiringPi: wiringPiSetupSys called\n") ;

	piBoardId (&OrangePiModel) ;

	switch (OrangePiModel)
	{
		case PI_MODEL_3:
			pinToGpio =  pinToGpio_3;
			physToGpio = physToGpio_3;
			break;
		case PI_MODEL_LTIE_2:
			pinToGpio =  pinToGpio_LITE_2;
			physToGpio = physToGpio_LITE_2;
			break;
		case PI_MODEL_ZERO:
			pinToGpio =  pinToGpio_LITE_2;
			physToGpio = physToGpio_LITE_2;
			break;
		case PI_MODEL_ZERO_PLUS_2:
			pinToGpio =  pinToGpio_ZERO_PLUS_2;
			physToGpio = physToGpio_ZERO_PLUS_2;
			break;
		case PI_MODEL_WIN:
			pinToGpio =  pinToGpio_WIN;
			physToGpio = physToGpio_WIN;
			break;
		case PI_MODEL_PRIME:
			pinToGpio =  pinToGpio_PRIME;
			physToGpio = physToGpio_PRIME;
			break;
		case PI_MODEL_PC_2:
			pinToGpio =  pinToGpio_PC_2;
			physToGpio = physToGpio_PC_2;
			break;
		case PI_MODEL_ZERO_PLUS:
			pinToGpio =  pinToGpio_ZERO_PLUS;
			physToGpio = physToGpio_ZERO_PLUS;
			break;
		case PI_MODEL_ZERO_2:
			pinToGpio =  pinToGpio_ZERO_2;
			physToGpio = physToGpio_ZERO_2;
			break;
		case PI_MODEL_ZERO_2_W:
			pinToGpio =  pinToGpio_ZERO_2_W;
			physToGpio = physToGpio_ZERO_2_W;
			break;
		case PI_MODEL_4A:
			pinToGpio =  pinToGpio_4A;
			physToGpio = physToGpio_4A;
			break;
		case PI_MODEL_800:
			pinToGpio =  pinToGpio_800;
			physToGpio = physToGpio_800;
			break;
		case PI_MODEL_4:
			pinToGpio =  pinToGpio_4;
			physToGpio = physToGpio_4;
			break;
		case PI_MODEL_4_LTS:
			pinToGpio =  pinToGpio_4_LTS;
			physToGpio = physToGpio_4_LTS;
			break;
		case PI_MODEL_RK3399:
			pinToGpio =  pinToGpio_RK3399;
			physToGpio = physToGpio_RK3399;
			break;
		case PI_MODEL_R1_PLUS:
			pinToGpio =  pinToGpio_R1_PLUS;
			physToGpio = physToGpio_R1_PLUS;
			break;
		case PI_MODEL_AI_PRO:
			pinToGpio =  pinToGpio_AIPRO;
			physToGpio = physToGpio_AIPRO;
			break;
		default:
			pinToGpio =  pinToGpio_H3;
			physToGpio = physToGpio_H3;
			break ;
	}

	// Open and scan the directory, looking for exported GPIOs, and pre-open
	//	the 'value' interface to speed things up for later
	for (pin = 1 ; pin < 28 ; ++pin)
	{
		tmpGpio = pinToGpio[pin];
		sprintf (fName, "/sys/class/gpio/gpio%d/value", tmpGpio) ;
		sysFds [pin] = open (fName, O_RDWR) ;
	}

	initialiseEpoch () ;

	wiringPiMode = WPI_MODE_GPIO_SYS;

	return 0 ;
}


/*
 * Read register value helper  
 */
unsigned int readR(unsigned int addr)
{
	unsigned int val = 0;
	unsigned int mmap_base;
	unsigned int mmap_seek;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			mmap_base = (addr & (0xfffff000));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3588_GPIO0_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio0_base + mmap_seek));
			else if(mmap_base == RK3588_GPIO1_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio1_base + mmap_seek));
			else if(mmap_base == RK3588_GPIO2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio2_base + mmap_seek));
			else if(mmap_base == RK3588_GPIO3_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio3_base + mmap_seek));
			else if(mmap_base == RK3588_GPIO4_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio4_base + mmap_seek));
			else if(mmap_base == RK3588_PMU1_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu1_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_BUS_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.bus_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.cur_base + mmap_seek));
			else if(mmap_base == RK3588_PMU1CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu1cur_base + mmap_seek));
			else if(mmap_base == RK3588_PMU2_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu2_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_VCCIO1_4_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio1_4_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_VCCIO3_5_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio3_5_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_VCCIO6_IOC_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio6_ioc_base + mmap_seek));
			else if(mmap_base == RK3588_PWM0_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm0_base + mmap_seek));
			else if(mmap_base == RK3588_PWM1_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm1_base + mmap_seek));
			else if(mmap_base == RK3588_PWM2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm2_base + mmap_seek));
			else if(mmap_base == RK3588_PWM3_BASE)
				val = *((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm3_base + mmap_seek));
			if (wiringPiDebug)
				printf("read %#x from [%#x]\n",val,addr);

			return val;

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			mmap_base = (addr & (0xfffff000));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3399_CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.cru_base + mmap_seek));
			else if(mmap_base == RK3399_GRF_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.grf_base + mmap_seek));
			else if(mmap_base == RK3399_GPIO2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio2_base + mmap_seek));
			else if(mmap_base == RK3399_GPIO1_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio1_base + mmap_seek));
			else if(mmap_base == RK3399_PMUCRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.pmucru_base + mmap_seek));
			else if(mmap_base == RK3399_PMUGRF_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.pmugrf_base + mmap_seek));
			else if(mmap_base == RK3399_GPIO4_BASE)
				val = *((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio4_base + mmap_seek));

			return val;

			break;

		case PI_MODEL_R1_PLUS:

			mmap_base = (addr & (0xfffff000));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3328_CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3328_soc_info_t.cru_base + mmap_seek));
			else if(mmap_base == RK3328_GRF_BASE)
				val = *((unsigned int *)((unsigned char *)rk3328_soc_info_t.grf_base + mmap_seek));
			else if(mmap_base == RK3328_GPIO2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3328_soc_info_t.gpio2_base + mmap_seek));
			else if(mmap_base == RK3328_GPIO3_BASE)
				val = *((unsigned int *)((unsigned char *)rk3328_soc_info_t.gpio3_base + mmap_seek));

			return val;

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			mmap_base = (addr & (0xfffff000));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3566_GPIO0_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio0_base + mmap_seek));
			else if(mmap_base == RK3566_GPIO1_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio1_base + mmap_seek));
			else if(mmap_base == RK3566_GPIO2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio2_base + mmap_seek));
			else if(mmap_base == RK3566_GPIO3_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio3_base + mmap_seek));
			else if(mmap_base == RK3566_GPIO4_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio4_base + mmap_seek));
			else if(mmap_base == RK3566_PMU_GRF_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.pmu_grf_base + mmap_seek));
			else if(mmap_base == RK3566_SYS_GRF_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.sys_grf_base + mmap_seek));
			else if(mmap_base == RK3566_CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.cru_base + mmap_seek));
			else if(mmap_base == RK3566_PMU_CRU_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.pmu_cru_base + mmap_seek));
			else if(mmap_base == RK3566_PWM2_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.pwm2_base + mmap_seek));
			else if(mmap_base == RK3566_PWM3_BASE)
				val = *((unsigned int *)((unsigned char *)rk3566_soc_info_t.pwm3_base + mmap_seek));

			if (wiringPiDebug)
				printf("read %#x from [%#x]\n",val,addr);

			return val;

			break;

		case PI_MODEL_3_PLUS:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr - mmap_base);

			if (mmap_base == S905D3_GPIO_BASE)
				val = *(s905d3_gpio_info_t.gpio_base + mmap_seek);
			else if (mmap_base == S905D3_GPIO_AO_BASE)
				val = *(s905d3_gpio_info_t.gpio_ao_base + mmap_seek);
			else if (mmap_base == S905D3_GPIO_PWM_BASE)
				val = *(s905d3_gpio_info_t.gpio_pwm_base + mmap_seek);
			else if (mmap_base == S905D3_GPIO_PWM_AO_BASE)
				val = *(s905d3_gpio_info_t.gpio_pwm_ao_base + mmap_seek);

			return val;

			break;

		case PI_MODEL_AI_PRO:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr & MAP_MASK);

			// gpio
			if(mmap_base == A310B_GPIO_BASE_GROUP0)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group0 + mmap_seek));
			else if(mmap_base == A310B_GPIO_BASE_GROUP1)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group1 + mmap_seek));
			else if(mmap_base == A310B_GPIO_BASE_GROUP2)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group2 + mmap_seek));
			else if(mmap_base == A310B_GPIO_BASE_GROUP3)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group3 + mmap_seek));
			else if(mmap_base == A310B_GPIO_BASE_GROUP4)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group4 + mmap_seek));
			else if(mmap_base == 0x160000)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group5 + mmap_seek));
			else if(mmap_base == 0x150000)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group7 + mmap_seek));
			// iomux
			else if(mmap_base == A310B_IOMUX_BASE_GROUP0)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group0 + mmap_seek));
			else if(mmap_base == A310B_IOMUX_BASE_GROUP1)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group1 + mmap_seek));
			else if(mmap_base == A310B_IOMUX_BASE_GROUP2)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group2 + mmap_seek));
			else if(mmap_base == A310B_IOMUX_BASE_GROUP3)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group3 + mmap_seek));
			else if(mmap_base == A310B_IOMUX_BASE_GROUP4)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group4 + mmap_seek));
			else if(mmap_base == 0x1d0000)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group5 + mmap_seek));
			else if(mmap_base == 0x140000)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group7 + mmap_seek));
			// pwm
			else if(mmap_base == A310B_PWM_BASE)
				val = *((unsigned int *) ((unsigned char *)a310b_gpio_info_t.pwm_base + mmap_seek));
			else
				printf("readR: mmap_base %x is error!\n", mmap_base);

			return val;

			break;

		case PI_MODEL_RV:
			val = 0;

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr - mmap_base);
			val = *((unsigned int *)((unsigned char *)jh7110_soc_info_t.sys_iomux_base + mmap_seek));
			return val;

			break;

		default:
			
			val = 0;
			mmap_base = (addr & 0xfffff000);
			mmap_seek = ((addr - mmap_base) >> 2);
			if(mmap_base == SUNXI_PWM_BASE) {
				val = *(sunxi_gpio_info_t.pwm + mmap_seek);
				if (wiringPiDebug) {
					printf("OPI: PWM: readR addr[%x]=[%x]\n",addr,val);
				}
				return val;
			}

			if (addr >= sunxi_gpio_info_t.r_gpio_base_addr)
				val = *(sunxi_gpio_info_t.r_gpio + mmap_seek);
			else
				val = *(sunxi_gpio_info_t.gpio + mmap_seek);

			return val;
			
			break;
	}

	return -1;
}

/*
 * Wirte value to register helper
 */
void writeR(unsigned int val, unsigned int addr)
{
	unsigned int mmap_base;
	unsigned int mmap_seek;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			mmap_base = (addr & (~0xfff));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3588_GPIO0_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio0_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_GPIO1_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio1_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_GPIO2_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio2_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_GPIO3_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio3_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_GPIO4_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.gpio4_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PMU1_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu1_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_BUS_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.bus_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_CRU_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.cur_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PMU1CRU_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu1cur_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PMU2_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pmu2_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_VCCIO1_4_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio1_4_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_VCCIO3_5_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio3_5_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_VCCIO6_IOC_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.vccio6_ioc_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PWM0_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm0_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PWM1_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm1_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PWM2_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm2_base + mmap_seek)) = val;
			else if(mmap_base == RK3588_PWM3_BASE)
				*((unsigned int *)((unsigned char *)rk3588_soc_info_t.pwm3_base + mmap_seek)) = val;

			if (wiringPiDebug)
				printf("write %#x to [%#x]\n",val,addr);

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			mmap_base = (addr & (~0xfff));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3399_CRU_BASE) 
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.cru_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_GRF_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.grf_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_GPIO2_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio2_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_GPIO1_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio1_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_PMUCRU_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.pmucru_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_PMUGRF_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.pmugrf_base + mmap_seek)) = val;
			else if(mmap_base == RK3399_GPIO4_BASE)
				*((unsigned int *)((unsigned char *)rk3399_soc_info_t.gpio4_base + mmap_seek)) = val;

			break;

		case PI_MODEL_R1_PLUS:

			mmap_base = (addr & (~0xfff));
			mmap_seek = (addr - mmap_base);
			if(mmap_base == RK3328_CRU_BASE)
				*((unsigned int *)((unsigned char *)rk3328_soc_info_t.cru_base + mmap_seek)) = val;
			else if(mmap_base == RK3328_GRF_BASE)
				*((unsigned int *)((unsigned char *)rk3328_soc_info_t.grf_base + mmap_seek)) = val;
			else if(mmap_base == RK3328_GPIO2_BASE)
				*((unsigned int *)((unsigned char *)rk3328_soc_info_t.gpio2_base + mmap_seek)) = val;
			else if(mmap_base == RK3328_GPIO3_BASE)
				*((unsigned int *)((unsigned char *)rk3328_soc_info_t.gpio3_base + mmap_seek)) = val;

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			mmap_base = (addr & (~0xfff));
			mmap_seek = (addr - mmap_base);

			if(mmap_base == RK3566_GPIO0_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio0_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_GPIO1_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio1_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_GPIO2_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio2_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_GPIO3_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio3_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_GPIO4_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.gpio4_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_PMU_GRF_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.pmu_grf_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_SYS_GRF_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.sys_grf_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_CRU_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.cru_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_PMU_CRU_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.pmu_cru_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_PWM2_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.pwm2_base + mmap_seek)) = val;
			else if(mmap_base == RK3566_PWM3_BASE)
				*((unsigned int *)((unsigned char *)rk3566_soc_info_t.pwm3_base + mmap_seek)) = val;

			if (wiringPiDebug)
				printf("write %#x to [%#x]\n",val,addr);

			break;

		case PI_MODEL_3_PLUS:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr - mmap_base);

			if (mmap_base == S905D3_GPIO_BASE) {
				*(s905d3_gpio_info_t.gpio_base + mmap_seek) = val;
			} else if (mmap_base == S905D3_GPIO_AO_BASE) {
				*(s905d3_gpio_info_t.gpio_ao_base + mmap_seek) = val;
			} else if (mmap_base == S905D3_GPIO_PWM_BASE) {
				*(s905d3_gpio_info_t.gpio_pwm_base + mmap_seek) = val;
			} else if (mmap_base == S905D3_GPIO_PWM_AO_BASE) {
				*(s905d3_gpio_info_t.gpio_pwm_ao_base + mmap_seek) = val;
			}

			break;

		case PI_MODEL_AI_PRO:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr & MAP_MASK);

			// gpio
			if(mmap_base == A310B_GPIO_BASE_GROUP0)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group0 + mmap_seek)) = val;
			else if(mmap_base == A310B_GPIO_BASE_GROUP1)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group1 + mmap_seek)) = val;
			else if(mmap_base == A310B_GPIO_BASE_GROUP2)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group2 + mmap_seek)) = val;
			else if(mmap_base == A310B_GPIO_BASE_GROUP3)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group3 + mmap_seek)) = val;
			else if(mmap_base == A310B_GPIO_BASE_GROUP4)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group4 + mmap_seek)) = val;
			else if(mmap_base == 0x160000)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group5 + mmap_seek)) = val;
			else if(mmap_base == 0x150000)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.gpio_base_group7 + mmap_seek)) = val;
			// iomux
			else if(mmap_base == A310B_IOMUX_BASE_GROUP0)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group0 + mmap_seek)) = val;
			else if(mmap_base == A310B_IOMUX_BASE_GROUP1)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group1 + mmap_seek)) = val;
			else if(mmap_base == A310B_IOMUX_BASE_GROUP2)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group2 + mmap_seek)) = val;
			else if(mmap_base == A310B_IOMUX_BASE_GROUP3)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group3 + mmap_seek)) = val;
			else if(mmap_base == A310B_IOMUX_BASE_GROUP4)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group4 + mmap_seek)) = val;
			else if(mmap_base == 0x1d0000)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group5 + mmap_seek)) = val;
			else if(mmap_base == 0x140000)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.iomux_base_group7 + mmap_seek)) = val;
			// pwm
			else if(mmap_base == A310B_PWM_BASE)
				*((unsigned int *) ((unsigned char *)a310b_gpio_info_t.pwm_base + mmap_seek)) = val;
			else
				printf("writeR: mmap_base %x is error!\n", mmap_base);

			break;

		case PI_MODEL_RV:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = (addr - mmap_base);
			*((unsigned int *)((unsigned char *)jh7110_soc_info_t.sys_iomux_base + mmap_seek)) = val;
			break;

		default:

			mmap_base = (addr & 0xfffff000);
			mmap_seek = ((addr - mmap_base) >> 2);
			if (mmap_base == SUNXI_PWM_BASE) {
				*(sunxi_gpio_info_t.pwm + mmap_seek) = val;
				if (wiringPiDebug ){
					printf("OPI: PWM: writeR addr[%x]=[%x]\n",addr,val);
				}
				return;
			}

			if (addr >= sunxi_gpio_info_t.r_gpio_base_addr)
				*(sunxi_gpio_info_t.r_gpio + mmap_seek) = val;
			else
				*(sunxi_gpio_info_t.gpio + mmap_seek) = val;

			break;
	}
}

int orangepi_get_gpio_mode(int pin)
{
	unsigned int regval = 0;
	unsigned int bank   = pin >> 5;
	unsigned int index  = pin - (bank << 5);
	unsigned int phyaddr = 0;
	unsigned char mode = -1;
	unsigned int grf_phyaddr = 0, ddr_phyaddr = 0;
	unsigned int rk3588_pmu1_ioc_phyaddr;
	unsigned int rk3588_bus_ioc_phyaddr;
	unsigned int iomux_val = 0; 			//for ai pro
	unsigned int iomux_phyaddr = 0, gpio_dir_phyaddr = 0;	//for ai pro
	unsigned int offset, shift;
	unsigned int doen, reg_doen;

	switch (OrangePiModel)
	{
		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			offset = ((index - ((index >> 3) << 3)));
			if(bank == 1){
				grf_phyaddr = RK3399_PMUGRF_BASE + ((index >> 3) << 2) + 0x10;
				ddr_phyaddr = RK3399_GPIO1_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}	
			else if(bank == 2){
				grf_phyaddr = RK3399_GRF_BASE + ((index >> 3) << 2);
				ddr_phyaddr = RK3399_GPIO2_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}
			else if(bank == 4){
				grf_phyaddr = RK3399_GRF_BASE + ((index >> 3) << 2) +0x20;
				ddr_phyaddr = RK3399_GPIO4_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				regval = readR(grf_phyaddr);
				mode = (regval >> (offset << 1)) & 0x3;//获取控制模式的那两位的值
				if(mode == 0){ //如果是gpio模式
					regval = readR(ddr_phyaddr);//获取gpio方向寄存器的值
					return (regval >> index) & 1;//index对应的gpio的方向值，0为in，1为out
				}
				return mode + 1;//如果不是gpio模式，返回的alt，从2开始，0和1是in和out
			}
			break;

		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			rk3588_bus_ioc_phyaddr = RK3588_BUS_IOC_BASE + (0x20 * bank) + ((index >> 2) << 2);
			if(bank == 0){
				if (index >= 12)
					rk3588_pmu1_ioc_phyaddr = RK3588_PMU2_IOC_BASE + ((index - 12) >> 2 << 2);
				else
					rk3588_pmu1_ioc_phyaddr = RK3588_PMU1_IOC_BASE + (index >> 2 << 2);

				ddr_phyaddr = RK3588_GPIO0_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
			}
			else if(bank == 1){
				ddr_phyaddr = RK3588_GPIO1_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
			}
			else if(bank == 2){
				ddr_phyaddr = RK3588_GPIO2_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
			}
			else if(bank == 3){
				ddr_phyaddr = RK3588_GPIO3_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
			}
			else if(bank == 4){
				ddr_phyaddr = RK3588_GPIO4_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
			}

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {

				if ( bank == 0 ) {
					regval = readR(rk3588_pmu1_ioc_phyaddr);
					mode = (regval >> ((index % 4) << 2)) & 0xf;
					if(mode == 0x8)
						regval = readR(rk3588_bus_ioc_phyaddr);
				}
				else
					regval = readR(rk3588_bus_ioc_phyaddr);

				mode = (regval >> ((index % 4) << 2)) & 0xf;//获取控制模式的那四位的值
				if(mode == 0){ //如果是gpio模式
					regval = readR(ddr_phyaddr);	//获取gpio方向寄存器的值
					return (regval >> (index % 16)) & 0x1;		//index对应的gpio的方向值，0为in，1为out
				}

				return mode + 1; //如果不是gpio模式，返回的alt，从2开始，0和1是in和out
			}
			break;

		case PI_MODEL_R1_PLUS:

			offset = ((index - ((index >> 3) << 3)));
			if(bank == 2)
			{
				//ddr_phyaddr = GPIO2_BASE + GPIO_SWPORTA_DDR_OFFSET;
				ddr_phyaddr = 0xff230004;
				//grf_phyaddr = GRF_BASE + ((index >> 3) << 2) + 0x10;
				if(0 == (index >> 3))//gpio2_ax
				{
					grf_phyaddr = RK3328_GRF_BASE + 0x20;
				}
				else if(3 == (index >> 3))//gpio2_dx
				{
					grf_phyaddr = RK3328_GRF_BASE + 0x34;
				}
			}
			else if(bank == 3)
			{
				//grf_phyaddr  = GRF_BASE + ((index >> 3) << 2) +0x20;
				ddr_phyaddr = RK3328_GPIO3_BASE + RK3328_GPIO_SWPORTA_DDR_OFFSET;
				if (0 == (index >> 3))
				{
					if(4 == offset)//gpio3_a4
					{
						grf_phyaddr  = RK3328_GRF_BASE + 0x38;
					}
					else//gpio3_a567
					{
						grf_phyaddr  = RK3328_GRF_BASE + 0x3c;
					}
				}
				else if(2 == (index >> 3)) //gpio3_c
				{
					grf_phyaddr  = RK3328_GRF_BASE + 0x48;
				}
			}

			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(grf_phyaddr);
				writeR(0xffff9877, 0xff440240);

				if(3 == bank && (0 == (index >> 3))) //gpio3_ax需要写3位
				{
					mode = (regval >> ((offset % 5) * 3)) & 0x7;
				}
				else
				{
					mode = (regval >> (offset << 1)) & 0x3;
				}
				if(mode == 0){
					regval = readR(ddr_phyaddr);
					return (regval >> index) & 1;
				}
				return mode + 1;
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if(bank == 0){
				grf_phyaddr = RK3566_PMU_GRF_BASE + RK3566_PMU_GRF_GPIO0A_IOMUX_L_OFFSET + ((pin >> 2) << 2);
				ddr_phyaddr = RK3566_GPIO0_BASE + RK3566_GPIO_SWPORT_DDR_L_OFFSET + ((index >> 4) << 2);
			}
			else{
				grf_phyaddr = RK3566_SYS_GRF_BASE + RK3566_GRF_GPIO1A_IOMUX_L_OFFSET + (((pin - 32) >> 2) << 2);
				ddr_phyaddr = RK3566_GPIO1_BASE + ((bank - 1) << 16) + RK3566_GPIO_SWPORT_DDR_L_OFFSET + ((index >> 4) << 2);
			}

			offset = (index % 4) << 2;

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				regval = readR(grf_phyaddr);
				mode = (regval >> offset) & 0x7;

				if(mode == 0){ //如果是gpio模式
					regval = readR(ddr_phyaddr);//获取gpio方向寄存器的值
					return (regval >> (index % 16)) & 0x1;//index对应的gpio的方向值，0为in，1为out
				}
				return mode + 1;//如果不是gpio模式，返回的alt，从2开始，0和1是in和out
			}
			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				regval = readR(S905D3_GPIO_MUX);
				mode = (regval >> S905D3_GPIO_MUX_OFFSET) & 0x7;

				if(mode == 0){ //如果是gpio模式
					regval = readR(S905D3_GPIO_OUT_EN);//获取gpio方向寄存器的值
					return ((regval >> S905D3_GPIO_OUT_EN_OFFSET) + 1) & 0x1;//0为out，1为in
				}
				return mode + 1;//如果不是gpio模式，返回的alt，从2开始，0和1是out和in
			}
			break;

		case PI_MODEL_AI_PRO:

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				switch (bank) {
                                        case 0:
                                                gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP0 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index >= 0 && index <= 11)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0x10 + index * 4;
                                                else if (index >= 12 && index <= 19)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xac + (index - 12) * 4;
                                                else if (index >= 20 && index <= 23)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xd4 + (index - 20) * 4;
                                                else if (index >= 24 && index <= 25)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xfc + (index - 24) * 4;
                                                else if (index >= 26 && index <= 27)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0x114 + (index - 26) * 4;

                                                if ( (index >> 4 && index <= 11) || (index >= 26 && index <= 27) )
                                                        iomux_val = 0;
                                                else
                                                        iomux_val = 3;

                                                break;
                                        case 1:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP1 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 1)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0xcc + index * 4;
						else if (index >= 2 && index <= 7)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0xe4 + (index - 2) * 4;
						else if (index >= 8 && index <= 11)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0x11c + (index - 8) * 4;

						if (index >= 8 && index <= 9)
							iomux_val = 0;
						else
							iomux_val = 3;

						break;
                                        case 2:
                                                gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP2 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index >= 9 && index <= 10)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP2 + 0x0 + (index - 9) * 4;
                                                else if (index >= 11 && index <= 31)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP2 + 0x28 + (index - 11) * 4;

                                                iomux_val = 3;
                                                break;
                                        case 3:
                                                gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP3 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index >= 0 && index <= 7)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP3 + index * 4;

                                                iomux_val = 3;
                                                break;
                                        case 4:
                                                gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP4 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index >= 0 && index <= 1)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0xbc + index * 4;
                                                else if (index >= 2 && index <= 22)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0x68 + (index - 2) * 4;
                                                else if (index >= 23 && index <= 24)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0xc4 + (index - 23) * 4;

                                                if (index >= 0 && index <= 1)
                                                        iomux_val = 0;
                                                else
                                                        iomux_val = 3;
                                                break;
                                        case 5:
                                                gpio_dir_phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP5 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index >= 0 && index <= 19)
                                                        iomux_phyaddr = A310B_IOMUX_BASE_GROUP5 + index * 4;

                                                iomux_val = 3;
                                                break;
                                        case 7:
                                                gpio_dir_phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP7 + A310B_GPIO_DIRECTION_OFFSET;

                                                if (index == 1)
                                                        iomux_phyaddr = (unsigned int)A310B_IOMUX_BASE_GROUP7;
                                                else if (index >= 2 && index <= 13)
                                                        iomux_phyaddr = (unsigned int)A310B_IOMUX_BASE_GROUP7 + 0x30 + (index - 2) * 4;

                                                if (index == 1)
                                                        iomux_val = 0;
                                                else
                                                        iomux_val = 3;
                                                break;
                                        default:
                                                printf("bank is error!!\n");
						break;
				}

				regval = readR(iomux_phyaddr);
				if (regval == iomux_val) {
					regval = readR(gpio_dir_phyaddr);
					mode = (regval >> index) & 0x1;
				}
				else if (regval == 0 && pin == 33)
					mode = 2;
				else
					mode = 3;
			}

			return mode;

			break;

		case PI_MODEL_RV:
			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				offset = 4 * (pin / 4);
				shift  = 8 * (pin % 4);
				reg_doen = JH7110_SYS_IOMUX_BASE + JH7110_SYS_DOEN_REG_BASE + offset;

				doen = readR(reg_doen);
				doen = (doen >> shift) & JH7110_DOEN_MASK;

				if(doen > 1)
					return doen;
				else
					return doen == JH7110_GPOEN_ENABLE ? 1 : 0;
			}

			break;

		default:

			offset = ((index - ((index >> 3) << 3)) << 2);

			if (bank == 11)
				phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + sunxi_gpio_info_t.r_gpio_base_offset + ((index >> 3) << 2);
			else
				phyaddr = sunxi_gpio_info_t.gpio_base_addr + sunxi_gpio_info_t.gpio_base_offset + (bank * sunxi_gpio_info_t.gpio_bank_offset) + ((index >> 3) << 2);

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(phyaddr);
				mode = (regval >> offset) & sunxi_gpio_info_t.gpio_cfg_mask;
			}

			return mode;

			break;
	}

	return -1;
}

void H618_set_pwm_reg(int pin,sunxi_gpio_info *sunxi_gpio_info_ptr)
{
	switch(pin) {
		case 227:
		case 267:
			sunxi_gpio_info_ptr->pwm_period = SUNXI_V2_PWM1_PERIOD;
			sunxi_gpio_info_ptr->pwm_ctrl = SUNXI_V2_PWM1_CTRL_REG;
			sunxi_gpio_info_ptr->pwm_clk = SUNXI_V2_PWM1_CLK_REG;
			sunxi_gpio_info_ptr->pwm_bit_en = SUNXI_V2_PWM1_EN;
			break;
		case 226:
		case 268:
			sunxi_gpio_info_ptr->pwm_period = SUNXI_V2_PWM2_PERIOD;
			sunxi_gpio_info_ptr->pwm_ctrl = SUNXI_V2_PWM2_CTRL_REG;
			sunxi_gpio_info_ptr->pwm_clk = SUNXI_V2_PWM2_CLK_REG;
			sunxi_gpio_info_ptr->pwm_bit_en = SUNXI_V2_PWM2_EN;
			break;
		case 225:
		case 270:
			sunxi_gpio_info_ptr->pwm_period = SUNXI_V2_PWM4_PERIOD;
			sunxi_gpio_info_ptr->pwm_ctrl = SUNXI_V2_PWM4_CTRL_REG;
			sunxi_gpio_info_ptr->pwm_clk = SUNXI_V2_PWM4_CLK_REG;
			sunxi_gpio_info_ptr->pwm_bit_en = SUNXI_V2_PWM4_EN;
			break;
		case 224:
		case 269:
			sunxi_gpio_info_ptr->pwm_period = SUNXI_V2_PWM3_PERIOD;
			sunxi_gpio_info_ptr->pwm_ctrl = SUNXI_V2_PWM3_CTRL_REG;
			sunxi_gpio_info_ptr->pwm_clk = SUNXI_V2_PWM3_CLK_REG;
			sunxi_gpio_info_ptr->pwm_bit_en = SUNXI_V2_PWM3_EN;
			break;
		default:
			fprintf(stderr,"gpio: the pin you choose doesn't support hardware PWM\n");
			break;
	}
}

void s905d3_set_gpio_reg(int pin,s905d3_gpio_info *s905d3_gpio_info_ptr)
{
	if (pin >= 476 && pin <= 491) { //GPIOA——16pin

		s905d3_gpio_info_ptr->gpio_out_en = S905D3_GPIOA_OUT_EN_REG;
		s905d3_gpio_info_ptr->gpio_out = S905D3_GPIOA_OUT_REG;
		s905d3_gpio_info_ptr->gpio_in = S905D3_GPIOA_IN_REG;
		s905d3_gpio_info_ptr->gpio_pupd = S905D3_GPIOA_PUPD_REG;
		s905d3_gpio_info_ptr->gpio_puen = S905D3_GPIOA_PUEN_REG;
		s905d3_gpio_info_ptr->gpio_out_offset = pin - 476;
		s905d3_gpio_info_ptr->gpio_out_en_offset = pin - 476;
		s905d3_gpio_info_ptr->gpio_in_offset = pin - 476;
		s905d3_gpio_info_ptr->gpio_pupd_offset = pin - 476;
		s905d3_gpio_info_ptr->gpio_puen_offset = pin - 476;

		if (pin <= 483) {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOA_MUX_REG1;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 476) * 4;
		} else {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOA_MUX_REG2;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 484) * 4;
			s905d3_gpio_info_ptr->pwm_duty_cycle = S905D3_PWM_DUTY_CYCLE_F_REG;
			s905d3_gpio_info_ptr->pwm_misc = S905D3_PWM_MISC_EF_REG;
		}

	} else if (pin >= 468 && pin <= 475) { //GPIOC——8pin

		s905d3_gpio_info_ptr->gpio_out_en = S905D3_GPIOC_OUT_EN_REG;
		s905d3_gpio_info_ptr->gpio_out = S905D3_GPIOC_OUT_REG;
		s905d3_gpio_info_ptr->gpio_in = S905D3_GPIOC_IN_REG;
		s905d3_gpio_info_ptr->gpio_pupd = S905D3_GPIOC_PUPD_REG;
		s905d3_gpio_info_ptr->gpio_puen = S905D3_GPIOC_PUEN_REG;
		s905d3_gpio_info_ptr->gpio_out_en_offset = pin - 468;
		s905d3_gpio_info_ptr->gpio_out_offset = pin - 468;
		s905d3_gpio_info_ptr->gpio_in_offset = pin - 468;
		s905d3_gpio_info_ptr->gpio_pupd_offset = pin - 468;
		s905d3_gpio_info_ptr->gpio_puen_offset = pin - 468;

		s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOC_MUX_REG;
		s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 468) * 4;

	} else if (pin >= 443 && pin <= 451) { //GPIOH——9pin

		s905d3_gpio_info_ptr->gpio_out_en = S905D3_GPIOH_OUT_EN_REG;
		s905d3_gpio_info_ptr->gpio_out = S905D3_GPIOH_OUT_REG;
		s905d3_gpio_info_ptr->gpio_in = S905D3_GPIOH_IN_REG;
		s905d3_gpio_info_ptr->gpio_pupd = S905D3_GPIOH_PUPD_REG;
		s905d3_gpio_info_ptr->gpio_puen = S905D3_GPIOH_PUEN_REG;
		s905d3_gpio_info_ptr->gpio_out_offset = pin - 443;
		s905d3_gpio_info_ptr->gpio_out_en_offset = pin - 443;
		s905d3_gpio_info_ptr->gpio_in_offset = pin - 443;
		s905d3_gpio_info_ptr->gpio_pupd_offset = pin - 443;
		s905d3_gpio_info_ptr->gpio_puen_offset = pin - 443;

		if (pin <= 450) {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOH_MUX_REG1;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 443) * 4;
		} else {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOH_MUX_REG2;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 451) * 4;
		}

	} else if (pin >= 412 && pin <= 423) { //GPIOAO——12pin

		s905d3_gpio_info_ptr->gpio_out_en = S905D3_GPIOAO_OUT_EN_REG;
		s905d3_gpio_info_ptr->gpio_out = S905D3_GPIOAO_OUT_REG;
		s905d3_gpio_info_ptr->gpio_in = S905D3_GPIOAO_IN_REG;
		s905d3_gpio_info_ptr->gpio_pupd = S905D3_GPIOAO_PUPD_REG;
		s905d3_gpio_info_ptr->gpio_puen = S905D3_GPIOAO_PUEN_REG;
		s905d3_gpio_info_ptr->gpio_out_offset = pin - 412;
		s905d3_gpio_info_ptr->gpio_out_en_offset = pin - 412;
		s905d3_gpio_info_ptr->gpio_in_offset = pin - 412;
		s905d3_gpio_info_ptr->gpio_pupd_offset = pin - 412;
		s905d3_gpio_info_ptr->gpio_puen_offset = pin - 412;

		if (pin <= 419) {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOAO_MUX_REG1;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 412) * 4;
			s905d3_gpio_info_ptr->pwm_duty_cycle = S905D3_PWM_DUTY_CYCLE_AO_C_REG;
			s905d3_gpio_info_ptr->pwm_misc = S905D3_PWM_MISC_AO_CD_REG;
		} else {
			s905d3_gpio_info_ptr->gpio_mux = S905D3_GPIOAO_MUX_REG2;
			s905d3_gpio_info_ptr->gpio_mux_offset = (pin - 420) * 4;
		}

	} else {
		fprintf(stderr,"gpio: the pin you selected is not available\n");
	}
}

void rk3588_set_pwm_reg(int pin, rk3588_soc_info * rk3588_soc_info_ptr)
{
	rk3588_soc_info_ptr->pwm_mux = RK3588_BUS_IOC_BASE + ((pin >> 2) << 2);
	rk3588_soc_info_ptr->pwm_mux_val = 0xb;
	rk3588_soc_info_ptr->pwm_mux_offset = (pin % 4) << 2;

	if (pin == 15 || pin == 16 || pin == 28) {
		rk3588_soc_info_ptr->pwm_mux = RK3588_PMU2_IOC_BASE + (((pin >> 2) - 3) << 2);
		rk3588_soc_info_ptr->pwm_mux_val = 0x3;
	}

	switch (pin)
	{
		case 15:
		case 34:
		case 58:  //PWM0CH0
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM0_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH0_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH0_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH0_CTRL;
			break;
		case 16:
		case 35:
		case 59:  //PWM0CH1
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM0_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH1_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH1_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH1_CTRL;
			break;
		case 39:
		case 28:
		case 50:  //PWM0CH3
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM0_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH3_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH3_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH3_CTRL;
			break;
		case 96:  //PWM2CH2
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM2_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH2_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH2_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH2_CTRL;
			break;
		case 97:  //PWM2CH3
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM2_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH3_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH3_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH3_CTRL;
			break;
		case 109:  //PWM3CH0
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM3_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH0_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH0_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH0_CTRL;
			break;
		case 47:
		case 110:  //PWM3CH1
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM3_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH1_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH1_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH1_CTRL;
			break;
		case 62:
		case 114:
		case 138:  //PWM3CH2
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM3_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH2_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH2_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH2_CTRL;
			break;
		case 54:
		case 63:
		case 139:  //PWM3CH3
			rk3588_soc_info_ptr->pwm_base = RK3588_PWM3_BASE;
			rk3588_soc_info_ptr->ch_period_hpr = RK3588_CH3_PERIOD_HPR;
			rk3588_soc_info_ptr->ch_duty_lpr = RK3588_CH3_DUTY_LPR;
			rk3588_soc_info_ptr->ch_crtl = RK3588_CH3_CTRL;
			break;
		default:
			printf("The pin you choose doesn't support hardware PWM.\n");
			switch (OrangePiModel)
			{
				case PI_MODEL_5_PRO:
					printf("You can select wiringPi pin 2/5/6/7/17/18/21/22 for PWM pin.\n");
					break;
				case PI_MODEL_5_MAX:
				case PI_MODEL_5_ULTRA:
					printf("You can select wiringPi pin 0/1/2/8/9/17/20/21/22/23 for PWM pin.\n");
					break;
				case PI_MODEL_CM5_TABLET:
					printf("You can select wiringPi pin 0/2/5/13 for PWM pin.\n");
					break;
				case PI_MODEL_5_PLUS:
				case PI_MODEL_AI_MAX:
					printf("You can select wiringPi pin 0/1/2/6/9/10/13/17/20/21/22 for PWM pin.\n");
					break;
				case PI_MODEL_5:
					printf("You can select wiringPi pin 0/2/5/8/9/10/14/16 for PWM pin.\n");
				case PI_MODEL_5B:
					printf("You can select wiringPi pin 0/2/5/8/9/10/13/15 for PWM pin.\n");
					break;
			}
			exit(1);
			break;
	}
}

void rk3566_set_pwm_reg(int pin,rk3566_soc_info *rk3566_soc_info_ptr)
{
	rk3566_soc_info_ptr->pwm_mux = RK3566_PWM_MUX_REG;

	switch (pin)
	{
		case 144:  //PWM2CH3
			rk3566_soc_info_ptr->cru_gate_con = RK3566_CRU_GATE_CON31;
			rk3566_soc_info_ptr->cru_gate_con_offset = 13;
			rk3566_soc_info_ptr->pwm_mux_val = 0x3;
			rk3566_soc_info_ptr->pwm_mux_offset = 0;
			rk3566_soc_info_ptr->pwm_base = RK3566_PWM2_BASE;
			rk3566_soc_info_ptr->ch_period_hpr = RK3566_CH3_PERIOD_HPR;
			rk3566_soc_info_ptr->ch_duty_lpr = RK3566_CH3_DUTY_LPR;
			rk3566_soc_info_ptr->ch_crtl = RK3566_CH3_CTRL;
			break;

		case 147:  //PWM3CH3
			rk3566_soc_info_ptr->cru_gate_con = RK3566_CRU_GATE_CON32;
			rk3566_soc_info_ptr->cru_gate_con_offset = 0;
			rk3566_soc_info_ptr->pwm_mux_val = 0x1;
			rk3566_soc_info_ptr->pwm_mux_offset = 12;
			rk3566_soc_info_ptr->pwm_base = RK3566_PWM3_BASE;
			rk3566_soc_info_ptr->ch_period_hpr = RK3566_CH3_PERIOD_HPR;
			rk3566_soc_info_ptr->ch_duty_lpr = RK3566_CH3_DUTY_LPR;
			rk3566_soc_info_ptr->ch_crtl = RK3566_CH3_CTRL;
			break;
	}
}

/*
 * Set GPIO Mode
 */
int orangepi_set_gpio_mode(int pin, int mode)
{
	unsigned int regval = 0;
	unsigned int bank = pin >> 5;
	unsigned int index = pin - (bank << 5);
	unsigned int phyaddr = 0;
	unsigned int offset, shift, mask;
	unsigned int cru_phyaddr =0, grf_phyaddr = 0, gpio_phyaddr = 0, ddr_phyaddr = 0;
	unsigned int cru_val = 0;
	unsigned int rk3588_pmu1_ioc_phyaddr;
	unsigned int rk3588_bus_ioc_phyaddr;
	unsigned int temp = 0;
	unsigned int bit_enable;
	unsigned int grf_val = 0;
	unsigned int iomux_val = 0; //for ai pro
	unsigned int iomux_phyaddr = 0, gpio_dir_phyaddr = 0; //for ai pro
	unsigned int pwm_prd_default = 0; //for ai pro pwm
	unsigned int dout, doen, dout_mask, doen_mask, reg_dout, reg_doen, reg_cfg;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			rk3588_bus_ioc_phyaddr = RK3588_BUS_IOC_BASE + (0x20 * bank) + ((index >> 2) << 2);
			if(bank == 0){
				if (index >= 12)
					rk3588_bus_ioc_phyaddr = RK3588_PMU2_IOC_BASE + ((index - 12) >> 2 << 2);
				else
					rk3588_bus_ioc_phyaddr = RK3588_PMU1_IOC_BASE + (index >> 2 << 2);

				ddr_phyaddr = RK3588_GPIO0_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_PMU1CRU_BASE + RK3588_PMU1CRU_GATE_CON5_OFFSET;
				cru_val = 0xffff9fff;
			}
			else if(bank == 1){
				ddr_phyaddr = RK3588_GPIO1_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON16_OFFSET;
				cru_val = 0xffff3fff;
			}
			else if(bank == 2){
				ddr_phyaddr = RK3588_GPIO2_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}
			else if(bank == 3){
				ddr_phyaddr = RK3588_GPIO3_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}
			else if(bank == 4){
				ddr_phyaddr = RK3588_GPIO4_BASE + RK3588_GPIO_SWPORT_DDR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				if(INPUT == mode)
				{
					regval = readR(cru_phyaddr);
					regval |= 0xffff0000;
					regval &= cru_val;
					writeR(regval, cru_phyaddr);
					regval = readR(cru_phyaddr);

					regval = readR(rk3588_bus_ioc_phyaddr);
					regval |= 0xffff0000;
					regval &= ~(0xf << ((index % 4) << 2));
					writeR(regval, rk3588_bus_ioc_phyaddr);
					regval = readR(rk3588_bus_ioc_phyaddr);

					regval = readR(ddr_phyaddr);
					regval |= 0xffff0000;
					regval &= ~(1 << (index % 16));
					writeR(regval, ddr_phyaddr);

					if (wiringPiDebug) {
						regval = readR(ddr_phyaddr);
						printf("Input mode set over reg val: %#x\n",regval);
					}
				} 
				else if(OUTPUT == mode)
				{
					regval = readR(cru_phyaddr);
					regval |= 0xffff0000;
					regval &= cru_val;
					writeR(regval, cru_phyaddr);
					regval = readR(cru_phyaddr);

					regval = readR(rk3588_bus_ioc_phyaddr);
					regval |= 0xffff0000;
					regval &= ~(0xf << ((index % 4) << 2));
					writeR(regval, rk3588_bus_ioc_phyaddr);
					regval = readR(rk3588_bus_ioc_phyaddr);

					regval = readR(ddr_phyaddr);
					regval |= 0xffff0000;
					regval |= (1 << (index % 16));
					writeR(regval, ddr_phyaddr);

					if (wiringPiDebug){
						regval = readR(ddr_phyaddr);
						printf("OUTPUT mode set over reg val: %#x\n",regval);
					}
				}
				else if(PWM_OUTPUT == mode)
				{

					//set clk——busioc
					if (wiringPiDebug)
						printf(">>Set cru_busioc_clk_en\n");

					regval = readR(RK3588_CRU_GATE_CON19);
					regval &= 0xfffffffe;
					writeR(regval, RK3588_CRU_GATE_CON19);
					regval = readR(RK3588_CRU_GATE_CON19);

					//Set clk——pwm123
					if (wiringPiDebug)
						printf(">>Set cru_pwm123_clk_en\n");

					regval = readR(RK3588_CRU_GATE_CON15);
					regval &= ~(0x00000ff8);
					regval |= 0xffff0920;
					writeR(regval,RK3588_CRU_GATE_CON15);
					regval = readR(RK3588_CRU_GATE_CON15);

					//Set clk——pmu1pwm
					if (wiringPiDebug)
						printf(">>Set cru_pmu1pwm_clk_en\n");

					regval = readR(RK3588_PMU1CRU_GATE_CON1);
					regval &= ~(0x00007000);
					regval |= 0xffff4000;
					writeR(regval,RK3588_PMU1CRU_GATE_CON1);
					regval = readR(RK3588_PMU1CRU_GATE_CON1);

					rk3588_set_pwm_reg(pin, &rk3588_soc_info_t);

					//Set mux
					if (wiringPiDebug)
						printf(">>Set mux\n");

					regval = readR(RK3588_PWM_MUX);
					regval |= 0xffff0000;
					regval &= ~(0xf << RK3588_PWM_MUX_OFFSET);
					regval |= (RK3588_PWM_MUX_VAL << RK3588_PWM_MUX_OFFSET);
					writeR(regval, RK3588_PWM_MUX);
					regval = readR(RK3588_PWM_MUX);

					//clear all reg
					if (wiringPiDebug)
						printf(">>Clear all reg\n");

					writeR(0, RK3588_CH_PERIOD_HPR);
					regval = readR(RK3588_CH_PERIOD_HPR);

					writeR(0, RK3588_CH_DUTY_LPR);
					regval = readR(RK3588_CH_DUTY_LPR);

					writeR(0, RK3588_CH_CTRL);
					regval = readR(RK3588_CH_CTRL);

					//Set period
					if (wiringPiDebug)
						printf(">>Set period\n");

					regval = readR(RK3588_CH_PERIOD_HPR);
					regval = 1000;
					writeR(regval, RK3588_CH_PERIOD_HPR);
					regval = readR(RK3588_CH_PERIOD_HPR);

					//Set duty
					if (wiringPiDebug)
						printf(">>Set duty\n");

					regval = readR(RK3588_CH_DUTY_LPR);
					regval = 500;
					writeR(regval, RK3588_CH_DUTY_LPR);
					regval = readR(RK3588_CH_DUTY_LPR);

					//Set ctrl
					if (wiringPiDebug)
						printf(">>Set ctrl\n");

					/**
					 * frequency of clock: 24 MHz / 120 = 200 kHz
					 * frequency of PWM: 200 kHz / 1000 = 200 Hz
					 * period of PWM: 1 / 200 Hz = 0.005 s
					 * duty: 500/1000 = 50%
					 */
					regval = readR(RK3588_CH_CTRL);
					regval =  (0 << RK3588_RPT) \
						  | (60 << RK3588_SCALE) \
						  | (0 << RK3588_PRESCALE) \
						  | (0 << RK3588_CLK_SRC_SEL) \
						  | (1 << RK3588_CLK_SEL) \
						  | (1 << RK3588_FORCE_CLK_EN) \
						  | (1 << RK3588_CH_CNT_EN) \
						  | (0 << RK3588_CONLOCK) \
						  | (0 << RK3588_OUTPUT_MODE) \
						  | (0 << RK3588_INACTIVE_POL) \
						  | (1 << RK3588_DUTY_POL) \
						  | (1 << RK3588_PWM_MODE) \
						  | (1 << RK3588_PWM_EN);

					writeR(regval, RK3588_CH_CTRL);
					regval = readR(RK3588_CH_CTRL);
				}
				else
				{
					printf("Unknow mode\n");
				}
			}
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			offset = ((index - ((index >> 3) << 3)));

			if(bank == 1){
				cru_phyaddr = RK3399_PMUCRU_BASE + RK3399_PMUCRU_CLKGATE_CON1_OFFSET;
				grf_phyaddr = RK3399_PMUGRF_BASE + ((index >> 3) << 2) + 0x10;
				gpio_phyaddr = RK3399_GPIO1_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}

			else if(bank == 2){
				cru_phyaddr = RK3399_CRU_BASE + RK3399_CRU_CLKGATE_CON31_OFFSET;
				grf_phyaddr = RK3399_GRF_BASE + ((index >> 3) << 2);
				gpio_phyaddr = RK3399_GPIO2_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}
			else if(bank == 4){
				cru_phyaddr = RK3399_CRU_BASE + RK3399_CRU_CLKGATE_CON31_OFFSET;
				grf_phyaddr = RK3399_GRF_BASE + ((index >> 3) << 2) +0x20;
				gpio_phyaddr = RK3399_GPIO4_BASE + RK3399_GPIO_SWPORTA_DDR_OFFSET;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				if (wiringPiDebug)
					printf("Register[%#x]: %#x index:%d\n", phyaddr, regval, index);

				/* Set Input */
				if(INPUT == mode)
				{
					writeR(0xffff0180, cru_phyaddr);
					regval = readR(grf_phyaddr);
					regval |= 0x3 << ((offset << 1) | 0x10);
					regval &= ~(0x3 << (offset << 1));
					writeR(regval, grf_phyaddr);
					regval = readR(gpio_phyaddr);
					regval &= ~(1 << index);
					writeR(regval, gpio_phyaddr);

					if (wiringPiDebug){
						regval = readR(gpio_phyaddr);
						printf("Input mode set over reg val: %#x\n",regval);
					}
				}
				/* Set Output */
				else if(OUTPUT == mode) 
				{
					writeR(0xffff0180, cru_phyaddr);
					regval = readR(grf_phyaddr);
					regval |= 0x3 << ((offset << 1) | 0x10);
					regval &= ~(0x3 << (offset << 1));
					writeR(regval, grf_phyaddr);
					regval = readR(gpio_phyaddr);
					regval |= 1 << index;
					writeR(regval, gpio_phyaddr);

					if (wiringPiDebug)
					{
						regval = readR(gpio_phyaddr);
						printf("Out mode get value: 0x%x\n",regval);
					} 
				}
				else
				{
					printf("Unknow mode\n");
				}
			}
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_R1_PLUS:

			offset = ((index - ((index >> 3) << 3)));

			if(bank == 2)
			{
				cru_phyaddr = RK3328_CRU_BASE + RK3328_CRU_CLKGATE_CON16_OFFSET;
				//grf_phyaddr = GRF_BASE + ((index >> 3) << 2) + 0x10;
				gpio_phyaddr = RK3328_GPIO2_BASE + RK3328_GPIO_SWPORTA_DDR_OFFSET;
				if(0 == (index >> 3))//gpio2_ax
				{
					grf_phyaddr = RK3328_GRF_BASE + 0x20;
				}
				else if(3 == (index >> 3))//gpio2_dx
				{
					grf_phyaddr = RK3328_GRF_BASE + 0x34;
				}
			}
			else if(bank == 3)
			{
				cru_phyaddr  = RK3328_CRU_BASE + RK3328_CRU_CLKGATE_CON16_OFFSET;
				//grf_phyaddr  = GRF_BASE + ((index >> 3) << 2) +0x20;
				gpio_phyaddr = RK3328_GPIO3_BASE + RK3328_GPIO_SWPORTA_DDR_OFFSET;
				if (0 == (index >> 3))
				{
					if(4 == offset)//gpio3_a4
					{
						grf_phyaddr  = RK3328_GRF_BASE + 0x38;
					}
					else//gpio3_a567
					{
						grf_phyaddr  = RK3328_GRF_BASE + 0x3c;
					}
				}
				else if(2 == (index >> 3)) //gpio3_c
				{
					grf_phyaddr  = RK3328_GRF_BASE + 0x48;
				}
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				if (wiringPiDebug)
					printf("Register[%#x]: %#x index:%d\n", phyaddr, regval, index);

				/* Set Input */
				if(INPUT == mode)
				{
					writeR(0xffff9877, cru_phyaddr);

					regval = readR(grf_phyaddr);
					if(3 == bank && (0 == (index >> 3))) //gpio3_a iomux需要写3位
					{					
						regval |= 0xffff0000;
						regval &= ~(0x7 << ((offset % 5) * 3));
					}
					else //其他的写两位
					{
						regval |= 0xffff0000;
						regval &= ~(0x3 << (offset << 1));
					}
					writeR(regval, grf_phyaddr);		

					regval = readR(gpio_phyaddr);
					regval &= ~(1 << index);
					writeR(regval, gpio_phyaddr);
					if (wiringPiDebug)
					{
						regval = readR(gpio_phyaddr);
						printf("Input mode set over reg val: %#x\n",regval);
					}
				} 
				else if(OUTPUT == mode) 
				{ 
					/* Set Output */
					writeR(0xffff9877, cru_phyaddr);

					regval = readR(grf_phyaddr);
					if(3 == bank && (0 == (index >> 3))) //gpio3_a iomux需要写3位
					{					
						regval |= 0xffff0000;
						regval &= ~(0x7 << ((offset % 5) * 3));
					}
					else //其他的写两位
					{
						regval |= 0xffff0000;
						regval &= ~(0x3 << (offset << 1));
					}
					writeR(regval, grf_phyaddr);		

					regval = readR(gpio_phyaddr);
					regval |= 1 << index;
					writeR(regval, gpio_phyaddr);
					if (wiringPiDebug)
					{
						regval = readR(gpio_phyaddr);
						printf("Out mode get value: 0x%x\n",regval);
					}
				} 
				else 
				{
					printf("Unknow mode\n");
				}
			}
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if(bank == 0){
				cru_phyaddr = RK3566_PMU_CRU_BASE + RK3566_PMUCRU_PMUGATE_CON01_OFFSET;
				cru_val = ~((0x3 << 9) | (0x3 << (16 + 9)));
				grf_phyaddr = RK3566_PMU_GRF_BASE + RK3566_PMU_GRF_GPIO0A_IOMUX_L_OFFSET + ((pin >> 2) << 2);
				ddr_phyaddr = RK3566_GPIO0_BASE + RK3566_GPIO_SWPORT_DDR_L_OFFSET + ((index >> 4) << 2);
			}
			else{
				cru_phyaddr = RK3566_CRU_BASE + RK3566_CRU_GATE_CON31_OFFSET;
				cru_val = ~((0xff << 2) | (0xff << (16 + 2)));
				grf_phyaddr = RK3566_SYS_GRF_BASE + RK3566_GRF_GPIO1A_IOMUX_L_OFFSET + (((pin - 32) >> 2) << 2);
				ddr_phyaddr = RK3566_GPIO1_BASE + ((bank - 1) << 16) + RK3566_GPIO_SWPORT_DDR_L_OFFSET + ((index >> 4) << 2);
			}

			offset = (index % 4) << 2;
			bit_enable = 0x7 << (16 + offset);
			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				if (INPUT == mode)
				{
					regval = readR(cru_phyaddr);
					regval &= cru_val;
					writeR(regval, cru_phyaddr);
					regval = readR(cru_phyaddr);

					regval = readR(grf_phyaddr);
					regval |= bit_enable;
					regval &= ~(0x7 << offset);
					writeR(regval, grf_phyaddr);
					regval = readR(grf_phyaddr);

					regval = readR(ddr_phyaddr);
					regval |= 0x1 << (16 + (index % 16));
					regval &= ~(1 << (index % 16));
					writeR(regval, ddr_phyaddr);
					regval = readR(ddr_phyaddr);
				}
				else if (OUTPUT == mode)
				{
					regval = readR(cru_phyaddr);
					regval &= cru_val;
					writeR(regval, cru_phyaddr);
					regval = readR(cru_phyaddr);

					regval = readR(grf_phyaddr);
					regval |= bit_enable;
					regval &= ~(0x7 << offset);
					writeR(regval, grf_phyaddr);
					regval = readR(grf_phyaddr);

					regval = readR(ddr_phyaddr);
					regval |= 0x1 << (16 + (index % 16));
					regval |= (1 << (index % 16));
					writeR(regval, ddr_phyaddr);
					regval = readR(ddr_phyaddr);
				}
				else if (PWM_OUTPUT == mode)
				{
					/*//set clk——busioc
					  if (wiringPiDebug)
					  printf(">>Set cru_busioc_clk_en\n");

					  regval = readR(RK3588_CRU_GATE_CON19);
					  regval &= 0xfffffffe;
					  writeR(regval,RK3588_CRU_GATE_CON19);
					  regval = readR(RK3588_CRU_GATE_CON19);*/

					rk3566_set_pwm_reg(pin,&rk3566_soc_info_t);

					//Set clk——pwm
					if (wiringPiDebug)
						printf(">>Set cru_pwm_clk_en\n");

					regval = readR(RK3566_CRU_GATE_CON);
					regval &= ~(0x7 << RK3566_CRU_GATE_CON_OFFSET);
					regval |= (0xffff0000 + (0x4 <<  RK3566_CRU_GATE_CON_OFFSET));
					writeR(regval,RK3566_CRU_GATE_CON);
					regval = readR(RK3566_CRU_GATE_CON);

					//Set mux
					if (wiringPiDebug)
						printf(">>Set mux\n");

					regval = readR(RK3566_PWM_MUX);
					regval |= 0xffff0000;
					regval &= ~(0xf << RK3566_PWM_MUX_OFFSET);
					regval |= (RK3566_PWM_MUX_VAL << RK3566_PWM_MUX_OFFSET);
					writeR(regval, RK3566_PWM_MUX);
					regval = readR(RK3566_PWM_MUX);

					//clear all reg
					if (wiringPiDebug)
						printf(">>Clear all reg\n");

					writeR(0, RK3566_CH_PERIOD_HPR);
					regval = readR(RK3566_CH_PERIOD_HPR);

					writeR(0, RK3566_CH_DUTY_LPR);
					regval = readR(RK3566_CH_DUTY_LPR);

					writeR(0, RK3566_CH_CTRL);
					regval = readR(RK3566_CH_CTRL);

					//Set period
					if (wiringPiDebug)
						printf(">>Set period\n");

					regval = readR(RK3566_CH_PERIOD_HPR);
					regval = 1000;
					writeR(regval, RK3566_CH_PERIOD_HPR);
					regval = readR(RK3566_CH_PERIOD_HPR);

					//Set duty
					if (wiringPiDebug)
						printf(">>Set duty\n");

					regval = readR(RK3566_CH_DUTY_LPR);
					regval = 500;
					writeR(regval, RK3566_CH_DUTY_LPR);
					regval = readR(RK3566_CH_DUTY_LPR);

					//Set ctrl
					if (wiringPiDebug)
						printf(">>Set ctrl\n");

					/**
					 * frequency of clock: 24 MHz / 120 = 200 kHz
					 * frequency of PWM: 200 kHz / 1000 = 200 Hz
					 * period of PWM: 1 / 200 Hz = 0.005 s
					 * duty: 500/1000 = 50%
					 */
					regval = readR(RK3566_CH_CTRL);
					regval =  (0 << RK3566_RPT) \
						  | (60 << RK3566_SCALE) \
						  | (0 << RK3566_PRESCALE) \
						  | (0 << RK3566_CLK_SRC_SEL) \
						  | (1 << RK3566_CLK_SEL) \
						  | (1 << RK3566_FORCE_CLK_EN) \
						  | (1 << RK3566_CH_CNT_EN) \
						  | (0 << RK3566_CONLOCK) \
						  | (0 << RK3566_OUTPUT_MODE) \
						  | (0 << RK3566_INACTIVE_POL) \
						  | (1 << RK3566_DUTY_POL) \
						  | (1 << RK3566_PWM_MODE) \
						  | (1 << RK3566_PWM_EN);

					writeR(regval, RK3566_CH_CTRL);
					regval = readR(RK3566_CH_CTRL);
				}
				else
				{
					printf("Unknow mode\n");
				}

			}
			else
			{
				printf("Pin mode failed!\n");
			}
			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			if(INPUT == mode) {
				/* Set Input */
				//Set mux
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_MUX, regval);

				regval &=  ~(0xF << S905D3_GPIO_MUX_OFFSET);

				writeR(regval, S905D3_GPIO_MUX);
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_MUX, regval);

				//set fsel
				regval = readR(S905D3_GPIO_OUT_EN);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_OUT_EN, regval);

				regval |=  1 << S905D3_GPIO_OUT_EN_OFFSET;

				writeR(regval, S905D3_GPIO_OUT_EN);
				regval = readR(S905D3_GPIO_OUT_EN);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_OUT_EN, regval);

			} else if (OUTPUT == mode) {
				/* Set Output */
				//Set mux
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_MUX, regval);

				regval &=  ~(0xF << S905D3_GPIO_MUX_OFFSET);

				writeR(regval, S905D3_GPIO_MUX);
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_MUX, regval);

				//set fsel
				regval = readR(S905D3_GPIO_OUT_EN);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_OUT_EN, regval);

				regval &=  ~(1 << S905D3_GPIO_OUT_EN_OFFSET);

				writeR(regval, S905D3_GPIO_OUT_EN);
				regval = readR(S905D3_GPIO_OUT_EN);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_OUT_EN, regval);

			} else if (PWM_OUTPUT == mode) {
				if (wiringPiDebug)
					printf("OPI: try wiringPi pin %d for PWM pin\n", pin);

				if (pin != 418 && pin != 487) {
					printf("the pin you choose doesn't support hardware PWM\n");
					printf("OPI:you can select wiringPi pin 418,487 for PWM pin\n");
					printf("or you can use it in softPwm mode\n");
					exit(1);
				}

				/* Set PWM_Output */
				//Set mux
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_GPIO_MUX, regval);

				regval &=  ~(0xF << S905D3_GPIO_MUX_OFFSET);
				regval |=  0x3 << S905D3_GPIO_MUX_OFFSET;

				if (wiringPiDebug)
					printf(">>>>>line:%d PWM mode ready to set val: 0x%x\n", __LINE__, regval);

				writeR(regval, S905D3_GPIO_MUX);
				regval = readR(S905D3_GPIO_MUX);

				if (wiringPiDebug)
					printf("<<<<<PWM mode set over reg val: 0x%x\n", regval);

				//clear all reg
				writeR(0, S905D3_PWM_DUTY_CYCLE);
				writeR(0, S905D3_PWM_MISC);

				//Set misc
				regval = readR(S905D3_PWM_MISC);

				/**
				 * frequency of clock: 24 MHz / 120 = 200 kHz
				 * frequency of PWM: 200 kHz / 1000 = 200 Hz
				 * period of PWM: 1 / 200 Hz = 0.005 s
				 * duty: 500/1000 = 50%
				 */

				regval =  (1 << S905D3_PWM_CLK_EN_1) \
					  | (119 << S905D3_PWM_CLK_DIV_1) \
					  | (1 << S905D3_PWM_CLK_EN_0) \
					  | (119 << S905D3_PWM_CLK_DIV_0) \
					  | (0 << S905D3_PWM_CLK_SEL_1) \
					  | (0 << S905D3_PWM_CLK_SEL_0) \
					  | (1 << S905D3_PWM_EN_1) \
					  | (1 << S905D3_PWM_EN_0);

				writeR(regval, S905D3_PWM_MISC);
				regval = readR(S905D3_PWM_MISC);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_PWM_MISC, regval);

				//Set duty_cycle
				orangepi_pwm_set_period(pin,1000);
				orangepi_pwm_set_act(pin,500);
				regval = readR(S905D3_PWM_DUTY_CYCLE);

				if (wiringPiDebug)
					printf("Register[%#x]: %#x\n", S905D3_PWM_DUTY_CYCLE, regval);
			}

			break;

		case PI_MODEL_AI_PRO:

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				switch (bank) {
					case 0:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP0 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 11)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0x10 + index * 4;
						else if (index >= 12 && index <= 19)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xac + (index - 12) * 4;
						else if (index >= 20 && index <= 23)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xd4 + (index - 20) * 4;
						else if (index >= 24 && index <= 25)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0xfc + (index - 24) * 4;
						else if (index >= 26 && index <= 27)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP0 + 0x114 + (index - 26) * 4;

						if ( (index >> 4 && index <= 11) || (index >= 26 && index <= 27) )
							iomux_val = 0;
						else
							iomux_val = 3;

						break;
					case 1:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP1 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 1)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0xcc + index * 4;
						else if (index >= 2 && index <= 7)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0xe4 + (index - 2) * 4;
						else if (index >= 8 && index <= 11)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP1 + 0x11c + (index - 8) * 4;

						if (index >= 8 && index <= 9)
							iomux_val = 0;
						else
							iomux_val = 3;

						if( (index >= 0 && index <=1) && PWM_OUTPUT == mode )
							iomux_val = 0;

						break;
					case 2:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP2 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 9 && index <= 10)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP2 + 0x0 + (index - 9) * 4;
						else if (index >= 11 && index <= 31)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP2 + 0x28 + (index - 11) * 4;

						iomux_val = 3;

						break;
					case 3:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP3 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 7)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP3 + index * 4;

						iomux_val = 3;

						break;
					case 4:
						gpio_dir_phyaddr = A310B_GPIO_BASE_GROUP4 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 1)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0xbc + index * 4;
						else if (index >= 2 && index <= 22)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0x68 + (index - 2) * 4;
						else if (index >= 23 && index <= 24)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP4 + 0xc4 + (index - 23) * 4;

						if (index >= 0 && index <= 1)
							iomux_val = 0;
						else
							iomux_val = 3;

						break;
					case 5:
						gpio_dir_phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP5 + A310B_GPIO_DIRECTION_OFFSET;

						if (index >= 0 && index <= 19)
							iomux_phyaddr = A310B_IOMUX_BASE_GROUP5 + index * 4;

						iomux_val = 3;

						break;
					case 7:
						gpio_dir_phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP7 + A310B_GPIO_DIRECTION_OFFSET;

						if (index == 1)
							iomux_phyaddr = (unsigned int)A310B_IOMUX_BASE_GROUP7;
						else if (index >= 2 && index <= 13)
							iomux_phyaddr = (unsigned int)A310B_IOMUX_BASE_GROUP7 + 0x30 + (index - 2) * 4;

						if (index == 1)
							iomux_val = 0;
						else
							iomux_val = 3;

						break;
					default:
						printf("bank is error!!\n");
						break;
				}

				writeR(iomux_val, iomux_phyaddr);

				if(INPUT == mode)
				{
					regval = readR(gpio_dir_phyaddr);
					regval &= ~(1 << index);
					writeR(regval, gpio_dir_phyaddr);

					if (wiringPiDebug) {
						regval = readR(gpio_dir_phyaddr);
						printf("Input mode set over reg val: %#x\n",regval);
					}
				}
				else if(OUTPUT == mode)
				{
					regval = readR(gpio_dir_phyaddr);
					regval |= (1 << index);
					writeR(regval, gpio_dir_phyaddr);

					if (wiringPiDebug){
						regval = readR(gpio_dir_phyaddr);
						printf("OUTPUT mode set over reg val: %#x\n",regval);
					}
				}
				else if(PWM_OUTPUT == mode)
				{
					if (pin != 33)
					{
						printf("the pin you choose doesn't support hardware PWM\n");
						printf("OPI:you can select wiringPi pin 33 for PWM pin\n");
						printf("or you can use it in softPwm mode\n");
						return -1;
					}

					pwm_prd_default = 150000;
					orangepi_pwm_set_period(pin, pwm_prd_default);
					orangepi_pwm_set_act(pin, pwm_prd_default / 2);

					//设置PWM低电平开始时刻。
					writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);

					//a310b_gpio_info_t.pwm_prd3_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_PRD3_OFFSET;
					//a310b_gpio_info_t.pwm_ch3_pwl_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWL_OFFSET;
					//a310b_gpio_info_t.pwm_ch3_pwh_phyaddr = (unsigned int)A310B_PWM_BASE + A310B_PWM_CH3_PWH_OFFSET;
					//pwm_prd_default = 150000;

					////设置PWM脉冲周期寄存器的值为1500000，period = 1 / 150000000 x 150000 = 1ms
					////PWM模块默认时钟频率为150MHz
					//writeR(pwm_prd_default, a310b_gpio_info_t.pwm_prd3_phyaddr); // 1ms  1khz

					////设置PWM低电平开始时刻。
					//writeR(0, a310b_gpio_info_t.pwm_ch3_pwl_phyaddr);

					////设置PWM高电平开始时刻，即可设置PWM占空比
					//writeR(pwm_prd_default / 2, a310b_gpio_info_t.pwm_ch3_pwh_phyaddr);
				}
			}

			break;

		case PI_MODEL_RV:

		        offset = 4 * (pin / 4);
			shift  = 8 * (pin % 4);
			dout_mask = JH7110_DOUT_MASK << shift;
			doen_mask = JH7110_DOEN_MASK << shift;
			reg_dout = JH7110_SYS_IOMUX_BASE + JH7110_SYS_DOUT_REG_BASE + offset;
			reg_doen = JH7110_SYS_IOMUX_BASE + JH7110_SYS_DOEN_REG_BASE + offset;
			reg_cfg = JH7110_SYS_IOMUX_BASE + JH7110_SYS_GPO_PDA_0_74_CFG + 4 * pin;

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				if (INPUT == mode) {
					doen = JH7110_GPOEN_DISABLE;
					dout = 0;
					doen <<= shift;
					dout <<= shift;
					dout |= readR(reg_dout) & ~dout_mask;
					writeR(dout, reg_dout);
					doen |= readR(reg_doen) & ~doen_mask;
					writeR(doen, reg_doen);
				} else {
					doen = JH7110_GPOEN_ENABLE;
					dout = 0;
					doen <<= shift;
					dout <<= shift;
					dout |= readR(reg_dout) & (~dout_mask);
					writeR(dout, reg_dout);
					doen |= readR(reg_doen) & ~doen_mask;
					writeR(doen, reg_doen);
				}
			}

			break;

		default:

			offset = ((index - ((index >> 3) << 3)) << 2);

			if (bank == 11)
				phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + sunxi_gpio_info_t.r_gpio_base_offset + ((index >> 3) << 2);
			else
				phyaddr = sunxi_gpio_info_t.gpio_base_addr + sunxi_gpio_info_t.gpio_base_offset + (bank * sunxi_gpio_info_t.gpio_bank_offset) + ((index >> 3) << 2);

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(phyaddr);
				if (wiringPiDebug)
					printf("Before read reg val: 0x%x offset:%d\n",regval,offset);
			
				if (wiringPiDebug)
					printf("Register[%#x]: %#x index:%d\n", phyaddr, regval, index);

				/* Set Input */
				if(INPUT == mode)
				{
					regval &= ~(sunxi_gpio_info_t.gpio_cfg_mask << offset);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);

					if (wiringPiDebug)
						printf("Input mode set over reg val: %#x\n",regval);
				}
				else if(OUTPUT == mode)
				{
					/* Set Output */
					regval &= ~(sunxi_gpio_info_t.gpio_cfg_mask << offset);
					regval |=  (1 << offset);

					if (wiringPiDebug)
						printf("Out mode ready set val: 0x%x\n",regval);

					writeR(regval, phyaddr);
					//printf("write regval = %#x\n", regval);
					regval = readR(phyaddr);

					if (wiringPiDebug)
						printf("Out mode get value: 0x%x\n",regval);
				}
				else if(PWM_OUTPUT == mode)
				{
					if (wiringPiDebug)
						printf("OPI: try wiringPi pin %d for PWM pin\n", pin);

					if (OrangePiModel == PI_MODEL_ZERO_2 && pin != 224 && pin != 225 && pin != 226 && pin != 227) {
						printf("the pin you choose doesn't support hardware PWM\n");
						printf("OPI:you can select wiringPi pin 224,225,226,227 for PWM pin\n");
						printf("or you can use it in softPwm mode\n");
						exit(1);
					} else if (OrangePiModel == PI_MODEL_ZERO_2_W && pin != 267 && pin != 268 && pin != 269 && pin != 270) {
						printf("the pin you choose doesn't support hardware PWM\n");
						printf("OPI:you can select wiringPi pin 267,268,269,270 for PWM pin\n");
						printf("or you can use it in softPwm mode\n");
						exit(1);
					}

					H618_set_pwm_reg(pin,&sunxi_gpio_info_t);

					// set pin PWMx to pwm mode
					regval &= ~(sunxi_gpio_info_t.gpio_cfg_mask << offset);
					if (OrangePiModel == PI_MODEL_ZERO_2)
						regval |= (0x4 << offset); // ALT4 PWM
					else if (OrangePiModel == PI_MODEL_ZERO_2_W)
						regval |= (0x5 << offset);
					else
						regval |= (0x3 << offset); // ALT3 PWM
					if (wiringPiDebug)
						printf(">>>>>line:%d PWM mode ready to set val: 0x%x\n", __LINE__, regval);

					writeR(regval, phyaddr);
					delayMicroseconds(200);
					regval = readR(phyaddr);

					if (wiringPiDebug)
						 printf("<<<<<PWM mode set over reg val: 0x%x\n", regval);

					//clear all reg
					writeR(0, SUNXI_PWM_CTRL_REG);
					writeR(0, SUNXI_PWM_PERIOD);

					//set default M:S to 1/2
					orangepi_pwm_set_period(pin,1024);
					orangepi_pwm_set_act(pin,512);
					sunxi_pwm_set_mode(PWM_MODE_MS);

					if (OrangePiModel == PI_MODEL_ZERO_2 || OrangePiModel == PI_MODEL_ZERO_2_W)
						orangepi_pwm_set_clk(pin,1);  //default clk:24M
					else
						orangepi_pwm_set_clk(pin,PWM_CLK_DIV_120); //default clk:24M/120
					delayMicroseconds(200);
				}
				else
				{
					printf("Unknow mode\n");
				}
			}
			else
			{
				printf("Pin mode failed!\n");
			}

			break;
	}

	return 0;
}

int orangepi_set_gpio_alt(int pin, int mode)
{
	unsigned int regval = 0;
	unsigned int bank   = pin >> 5;
	unsigned int index  = pin - (bank << 5);
	unsigned int phyaddr = 0;
	int offset = ((index - ((index >> 3) << 3)) << 2);

	if (bank == 11)
		phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + ((index >> 3) << 2);
	else
		phyaddr = sunxi_gpio_info_t.gpio_base_addr + (bank * sunxi_gpio_info_t.gpio_bank_offset) + ((index >> 3) << 2);

	/* Ignore unused gpio */
	if (ORANGEPI_PIN_MASK[bank][index] != -1)
	{
		if (wiringPiDebug)
			printf("Register[%#x]: %#x index:%d\n", phyaddr, regval, index);

		regval = readR(phyaddr);
		regval &= ~(sunxi_gpio_info_t.gpio_cfg_mask << offset);
		regval |=  (mode << offset);
		writeR(regval, phyaddr);
	}
	else
	{
		printf("Pin alt mode failed!\n");
	}

	return 0;
}

/*
 * OrangePi Digital write 
 */
int orangepi_digitalWrite(int pin, int value)
{
	unsigned int bank   = pin >> 5;
	unsigned int index  = pin - (bank << 5);
	unsigned int phyaddr = 0;
	unsigned int regval = 0;
	unsigned int cru_phyaddr =0, gpio_phyaddr = 0, dr_phyaddr = 0;
	unsigned int cru_val = 0;
	unsigned int temp = 0;
	unsigned int bit_enable = 0;
	unsigned int offset;
	unsigned int shift, dout_mask, reg_dout, dout, ddout;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			if(bank == 0){
				dr_phyaddr = RK3588_GPIO0_BASE + RK3588_GPIO_SWPORT_DR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_PMU1CRU_BASE + RK3588_PMU1CRU_GATE_CON5_OFFSET;
				cru_val = 0xffff9fff;
			}
			else if(bank == 1){
				dr_phyaddr = RK3588_GPIO1_BASE + RK3588_GPIO_SWPORT_DR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON16_OFFSET;
				cru_val = 0xffff3fff;
			}
			else if(bank == 2){
				dr_phyaddr = RK3588_GPIO2_BASE + RK3588_GPIO_SWPORT_DR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}
			else if(bank == 3){
				dr_phyaddr = RK3588_GPIO3_BASE + RK3588_GPIO_SWPORT_DR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}
			else if(bank == 4){
				dr_phyaddr = RK3588_GPIO4_BASE + RK3588_GPIO_SWPORT_DR_L_OFFSET + ((index / 16) << 2);
				cru_phyaddr = RK3588_CRU_BASE + RK3588_CRU_GATE_CON17_OFFSET;
				cru_val = 0xffffffc0;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(cru_phyaddr);
				regval &= cru_val;
				writeR(regval, cru_phyaddr);

				if(0 == value)
				{
					regval = readR(dr_phyaddr);
					regval |= 0xffff0000;
					regval &= ~(1 << (index % 16));
					writeR(regval, dr_phyaddr);
					regval = readR(dr_phyaddr);
					if (wiringPiDebug)
						printf("LOW val set over reg val: 0x%x\n", regval);
				}
				else
				{
					regval = readR(dr_phyaddr);
					regval |= 0xffff0000;
					regval |= (1 << (index % 16));
					writeR(regval, dr_phyaddr);
					regval = readR(dr_phyaddr);
					if (wiringPiDebug)
						printf("HIGH val set over reg val: 0x%x\n", regval);
				}
			} 
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			if(bank == 1)
			{
				phyaddr = RK3399_GPIO1_BASE + RK3399_GPIO_SWPORTA_DR_OFFSET;
				cru_phyaddr = RK3399_PMUCRU_BASE + RK3399_PMUCRU_CLKGATE_CON1_OFFSET;
			}
			else if(bank == 2)
			{
				phyaddr = RK3399_GPIO2_BASE + RK3399_GPIO_SWPORTA_DR_OFFSET;			
				cru_phyaddr = RK3399_CRU_BASE + RK3399_CRU_CLKGATE_CON31_OFFSET;
			}
			else if(bank == 4)
			{
				phyaddr = RK3399_GPIO4_BASE + RK3399_GPIO_SWPORTA_DR_OFFSET;			
				cru_phyaddr = RK3399_CRU_BASE + RK3399_CRU_CLKGATE_CON31_OFFSET;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{

				writeR(0xffff0180, cru_phyaddr);

				regval = readR(phyaddr);
				if (wiringPiDebug)
					printf("befor write reg val: 0x%x,index:%d\n", regval, index);

				if(0 == value)
				{
					regval &= ~(1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("LOW val set over reg val: 0x%x\n", regval);
				} 
				else
				{
					regval |= (1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("HIGH val set over reg val: 0x%x\n", regval);
				}
			} 
			else
			{
				printf("Pin mode failed!\n");
			}

			break;
		case PI_MODEL_R1_PLUS:
			
			if(bank == 2)
			{
				phyaddr = RK3328_GPIO2_BASE + RK3328_GPIO_SWPORTA_DR_OFFSET;			
				cru_phyaddr = RK3328_CRU_BASE + RK3328_CRU_CLKGATE_CON16_OFFSET;				
			}
			else if(bank == 3)
			{
				phyaddr = RK3328_GPIO3_BASE + RK3328_GPIO_SWPORTA_DR_OFFSET;			
				cru_phyaddr = RK3328_CRU_BASE + RK3328_CRU_CLKGATE_CON16_OFFSET;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				writeR(0xffff9877, cru_phyaddr);
				regval = readR(phyaddr);
				if (wiringPiDebug)
					printf("befor write reg val: 0x%x,index:%d\n", regval, index);

				if(0 == value)
				{
					regval &= ~(1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("LOW val set over reg val: 0x%x\n", regval);
				} 
				else
				{
					regval |= (1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("HIGH val set over reg val: 0x%x\n", regval);
				}
			} 
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if(bank == 0){
				dr_phyaddr = RK3566_GPIO0_BASE + RK3566_GPIO_SWPORT_DR_L_OFFSET + ((index >> 4) << 2);
				cru_phyaddr = RK3566_PMU_CRU_BASE + RK3566_PMUCRU_PMUGATE_CON01_OFFSET;
				cru_val = ~((0x3 << 9) | (0x3 << (16 + 9)));
			}
			else{
				dr_phyaddr = RK3566_GPIO1_BASE + ((bank - 1) << 16) + RK3566_GPIO_SWPORT_DR_L_OFFSET + ((index >> 4) << 2);
				cru_phyaddr = RK3566_CRU_BASE + RK3566_CRU_GATE_CON31_OFFSET;
				cru_val = ~((0xff << 2) | (0xff << (16 + 2)));
			}

			offset = index % 16;
			bit_enable = 0x1 << (16 + offset);

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(cru_phyaddr);
				regval &= cru_val;
				writeR(regval, cru_phyaddr);

				regval = readR(dr_phyaddr);

				if(wiringPiDebug)
					printf("read val(%#x) from register[%#x]\n", regval, dr_phyaddr);

				regval |= bit_enable;

				if(0 == value)
					regval &= ~(1 << offset);
				else
					regval |= (1 << offset);

				writeR(regval, dr_phyaddr);
				if (wiringPiDebug)
					printf("write val(%#x) to register[%#x]\n", regval, dr_phyaddr);

				regval = readR(dr_phyaddr);
				if (wiringPiDebug)
					printf("set over reg val: 0x%x\n", regval);
			} 
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(S905D3_GPIO_OUT);

				if(wiringPiDebug)
					printf("read val(%#x) from register[%#x]\n", regval, S905D3_GPIO_OUT);

				if(0 == value)
					regval &= ~(1 << S905D3_GPIO_OUT_OFFSET);
				else
					regval |= (1 << S905D3_GPIO_OUT_OFFSET);

				writeR(regval, S905D3_GPIO_OUT);

				if (wiringPiDebug)
					printf("write val(%#x) to register[%#x]\n", regval, S905D3_GPIO_OUT);

				regval = readR(S905D3_GPIO_OUT);

				if (wiringPiDebug)
					printf("set over reg val: 0x%x\n", regval);
			}
			else
			{
				printf("Pin mode failed!\n");
			}

			break;

		case PI_MODEL_AI_PRO:

			switch (bank) {
				case 0:
					phyaddr = A310B_GPIO_BASE_GROUP0 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 1:
					phyaddr = A310B_GPIO_BASE_GROUP1 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 2:
					phyaddr = A310B_GPIO_BASE_GROUP2 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 3:
					phyaddr = A310B_GPIO_BASE_GROUP3 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 4:
					phyaddr = A310B_GPIO_BASE_GROUP4 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 5:
					phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP5 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				case 7:
					phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP7 + A310B_GPIO_SET_VALUE_OFFSET;
					break;
				default:
					printf("bank is error!!\n");
					break;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(phyaddr);
				if (wiringPiDebug)
					printf("befor write reg val: 0x%x,index:%d\n", regval, index);

				if(0 == value)
				{
					regval &= ~(1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("LOW val set over reg val: 0x%x\n", regval);
				}
				else
				{
					regval |= (1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("HIGH val set over reg val: 0x%x\n", regval);
				}
			}
			else
				printf("Pin mode failed!\n");

			break;

		case PI_MODEL_RV:
			dout = 0;
			offset = 4 * (pin / 4);
			shift  = 8 * (pin % 4);
			dout_mask = JH7110_DOUT_MASK << shift;
			reg_dout = JH7110_SYS_IOMUX_BASE + JH7110_SYS_DOUT_REG_BASE + offset;

			dout <<= shift;

			if (ORANGEPI_PIN_MASK[bank][index] != -1) {
				ddout = (value ? 1 : 0) << shift;

				ddout |= readR(reg_dout) & ~dout_mask;
				writeR(ddout, reg_dout);
			}

			break;

		default:
			
			if (bank == 11)
			{
				phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + sunxi_gpio_info_t.r_gpio_base_offset + 0x10;
			}
			else
			{
				phyaddr = sunxi_gpio_info_t.gpio_base_addr + sunxi_gpio_info_t.gpio_base_offset + (bank * sunxi_gpio_info_t.gpio_bank_offset) + 0x10;
			}

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				regval = readR(phyaddr);
				if (wiringPiDebug)
					printf("befor write reg val: 0x%x,index:%d\n", regval, index);
				
				if(0 == value)
				{
					regval &= ~(1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("LOW val set over reg val: 0x%x\n", regval);
				} 
				else
				{
					regval |= (1 << index);
					writeR(regval, phyaddr);
					regval = readR(phyaddr);
					if (wiringPiDebug)
						printf("HIGH val set over reg val: 0x%x\n", regval);
				}
			} 
			else
			{
				printf("Pin mode failed!\n");
			}

			break;
	}

	return 0;
}

/*
 * OrangePi Digital Read
 */
int orangepi_digitalRead(int pin)
{
	int bank = pin >> 5;
	int index = pin - (bank << 5);
	int val;
	unsigned int phyaddr = 0;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			if(bank == 0)
				phyaddr = RK3588_GPIO0_BASE + RK3588_GPIO_EXT_PORT_OFFSET;
			else if(bank == 1)
				phyaddr = RK3588_GPIO1_BASE + RK3588_GPIO_EXT_PORT_OFFSET;
			else if(bank == 2)
				phyaddr = RK3588_GPIO2_BASE + RK3588_GPIO_EXT_PORT_OFFSET;
			else if(bank == 3)
				phyaddr = RK3588_GPIO3_BASE + RK3588_GPIO_EXT_PORT_OFFSET;
			else if(bank == 4)
				phyaddr = RK3588_GPIO4_BASE + RK3588_GPIO_EXT_PORT_OFFSET;

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			if(bank == 1)
				phyaddr = RK3399_GPIO1_BASE + RK3399_GPIO_EXT_PORTA_OFFSET;
			else if(bank == 2)
				phyaddr = RK3399_GPIO2_BASE + RK3399_GPIO_EXT_PORTA_OFFSET;
			else if(bank == 4)
				phyaddr = RK3399_GPIO4_BASE + RK3399_GPIO_EXT_PORTA_OFFSET;

			break;

		case PI_MODEL_R1_PLUS:

			if(bank == 2)
				phyaddr = RK3328_GPIO2_BASE + RK3328_GPIO_EXT_PORTA_OFFSET;
			else if(bank == 3)
				phyaddr = RK3328_GPIO3_BASE + RK3328_GPIO_EXT_PORTA_OFFSET;

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if(bank == 0)
				phyaddr = RK3566_GPIO0_BASE + RK3566_GPIO_EXT_PORT_OFFSET;
			else
				phyaddr = RK3566_GPIO1_BASE + ((bank - 1) << 16) + RK3566_GPIO_EXT_PORT_OFFSET;

			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);
			phyaddr = S905D3_GPIO_IN;

			break;

		case PI_MODEL_AI_PRO:

			switch (bank) {
				case 0:
					phyaddr = A310B_GPIO_BASE_GROUP0 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 1:
					phyaddr = A310B_GPIO_BASE_GROUP1 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 2:
					phyaddr = A310B_GPIO_BASE_GROUP2 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 3:
					phyaddr = A310B_GPIO_BASE_GROUP3 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 4:
					phyaddr = A310B_GPIO_BASE_GROUP4 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 5:
					phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP5 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				case 7:
					phyaddr = (unsigned int)A310B_GPIO_BASE_GROUP7 + A310B_GPIO_GET_VALUE_OFFSET;
					break;
				default:
					printf("bank is error!!\n");
			}

			break;

		case PI_MODEL_RV:
			phyaddr = JH7110_SYS_IOMUX_BASE + JH7110_SYS_GPIOIN_REG_BASE + 4 * (pin / GPIO_NUM_PER_WORD);

			break;

		default:

			if (bank == 11) 
				phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + sunxi_gpio_info_t.r_gpio_base_offset + 0x10;
			else
				phyaddr = sunxi_gpio_info_t.gpio_base_addr + sunxi_gpio_info_t.gpio_base_offset + (bank * sunxi_gpio_info_t.gpio_bank_offset) + 0x10;

			break;

	}

	if (ORANGEPI_PIN_MASK[bank][index] != -1)
	{
		val = readR(phyaddr);

		if (OrangePiModel == PI_MODEL_3_PLUS) {
			val = val >> S905D3_GPIO_IN_OFFSET;
		} else {
			val = val >> index;
		}

		val &= 1;

		if (wiringPiDebug)
			printf("Read reg val: 0x%#x, bank:%d, index:%d\n", val, bank, index);

		return val;
	}

	return 0;
}

void OrangePi_set_gpio_pullUpDnControl (int pin, int pud)
{
	unsigned int bank = pin >> 5;
	unsigned int index = pin - (bank << 5);
	unsigned int regval;
	unsigned int offset;
	unsigned int phyaddr = 0;
	unsigned int bit_enable;
	unsigned int bit_value = 0;

	switch (OrangePiModel)
	{
		case PI_MODEL_5: case PI_MODEL_5B:
		case PI_MODEL_5_PRO:
		case PI_MODEL_5_MAX:
		case PI_MODEL_5_ULTRA:
		case PI_MODEL_5_PLUS:
		case PI_MODEL_900:
		case PI_MODEL_CM5:
		case PI_MODEL_CM5_TABLET:
		case PI_MODEL_AI_MAX:

			if(bank == 0 && index < 12)
				phyaddr = RK3588_PMU1_IOC_BASE + RK3588_PMU1_IOC_GPIO0A_P + ((index >> 3) << 2);
			else if(bank == 0 && index > 11 && index < 31)
				phyaddr = RK3588_PMU2_IOC_BASE + RK3588_PMU2_IOC_GPIO0B_P + (((index - 8) >> 3) << 2);
			else if(bank == 1)
				phyaddr = RK3588_VCCIO1_4_IOC_BASE + RK3588_VCCIO1_4_IOC_GPIO1A_P + ((index >> 3) << 2);
			else if(bank < 4 || (bank == 4 && index > 17))
				phyaddr = RK3588_VCCIO3_5_IOC_BASE + RK3588_VCCIO3_5_IOC_GPIO2A_P + (((pin - 64) >> 3) << 2);
			else if(bank == 4 && index < 18)
				phyaddr = RK3588_VCCIO6_IOC_BASE + RK3588_VCCIO6_IOC_GPIO4A_P + ((index >> 3) << 2);

			offset = (index % 8) << 1;
			bit_enable = 3 << ( 16 + offset);

			/* */if (PUD_UP == pud)
				bit_value = 3;
			else if (PUD_DOWN == pud)
				bit_value = 1;
			else if (PUD_OFF == pud)
				bit_value = 0;

			break;

		case PI_MODEL_800: case PI_MODEL_4_LTS:
		case PI_MODEL_4:   case PI_MODEL_RK3399:

			/* */if ( bank > 1)
				phyaddr = RK3399_GRF_BASE    + RK3399_GRF_GPIO2_3_4_P_OFFSET  + (((pin - 64) >> 3) << 2);
			else if ( bank == 1 || pin < 16)
				phyaddr = RK3399_PMUGRF_BASE + RK3399_PMUGRF_GPIO0_1_P_OFFSET + (((pin - 0)  >> 3) << 2);
			else {
				printf("gpio0 Group c,d does not support PU/PD control\n");
				return ;
			}

			//offset = index - ((index >> 3) << 3);
			offset = (index % 8) << 1;
			bit_enable = 3 << ( 16 + offset);

			/* */if (PUD_UP == pud) {
					if ( pin < 8 || (bank == 2 && index > 15)) /* gpio0a, gpio2c, gpio2d */
						bit_value = 3;
					else
						bit_value = 1;
			}
			else if (PUD_DOWN == pud) {
				if ( pin < 8 || (bank == 2 && index > 15)) /* gpio0a, gpio2c, gpio2d */
					bit_value = 1;
				else
					bit_value = 2;
			}
			else if (PUD_OFF == pud) {
					bit_value = 0;
			}

			break;

		case PI_MODEL_CM4:
		case PI_MODEL_3B:

			if (bank == 0)
				phyaddr = RK3566_PMU_GRF_BASE + RK3566_PMU_GRF_GPIO0A_P_OFFSET  + (((pin - 0) >> 3) << 2);
			else
				phyaddr = RK3566_SYS_GRF_BASE + RK3566_GRF_GPIO1A_P_OFFSET + (((pin - 32)  >> 3) << 2);

			offset = (index % 8) << 1;
			bit_enable = 3 << ( 16 + offset);

			/* */if (PUD_UP == pud)
					bit_value = 1;
			else if (PUD_DOWN == pud)
					bit_value = 2;
			else if (PUD_OFF == pud)
					bit_value = 0;
			break;

		case PI_MODEL_3_PLUS:

			s905d3_set_gpio_reg(pin,&s905d3_gpio_info_t);

			/* Ignore unused gpio */
			if (ORANGEPI_PIN_MASK[bank][index] != -1)
			{
				if (PUD_UP == pud) {
					//Set puen
					regval = readR(S905D3_GPIO_PUEN);
					regval |= 1 << S905D3_GPIO_PUEN_OFFSET;
					writeR(regval, S905D3_GPIO_PUEN);

					//Set pupd
					regval = readR(S905D3_GPIO_PUPD);
					regval |= 1 << S905D3_GPIO_PUPD_OFFSET;
					writeR(regval, S905D3_GPIO_PUPD);

				} else if (PUD_DOWN == pud) {
					//Set puen
					regval = readR(S905D3_GPIO_PUEN);
					regval |= 1 << S905D3_GPIO_PUEN_OFFSET;
					writeR(regval, S905D3_GPIO_PUEN);

					//Set pupd
					regval = readR(S905D3_GPIO_PUPD);
					regval &= ~(1 << S905D3_GPIO_PUPD_OFFSET);
					writeR(regval, S905D3_GPIO_PUPD);

				} else if (PUD_OFF == pud) {
					//Disable puen
					regval = readR(S905D3_GPIO_PUEN);
					regval &= ~(1 << S905D3_GPIO_PUEN_OFFSET);
					writeR(regval, S905D3_GPIO_PUEN);
				}
			}

			return;

		case PI_MODEL_RV:

			phyaddr = JH7110_SYS_IOMUX_BASE + JH7110_SYS_GPO_PDA_0_74_CFG + 4 * pin;

			offset = 3;

			/* */if (PUD_UP == pud)
					bit_value = 1;
			else if (PUD_DOWN == pud)
					bit_value = 2;
			else if (PUD_OFF == pud)
					bit_value = 0;

			regval = readR(phyaddr);
			regval &= ~(3 << offset);
			regval |= (bit_value & 3) << offset;
			writeR(regval, phyaddr);

			return ;

		default:
			//int offset = ((index - ((index >> 4) << 4)) << 1);
			offset = ((index % 16) << 1);

			if (bank == 11)
				phyaddr = sunxi_gpio_info_t.r_gpio_base_addr + sunxi_gpio_info_t.r_gpio_base_offset + ((index >> 4) << 2) + sunxi_gpio_info_t.pull_offset;
			else
				phyaddr = sunxi_gpio_info_t.gpio_base_addr + sunxi_gpio_info_t.gpio_base_offset + (bank * sunxi_gpio_info_t.gpio_bank_offset) + ((index >> 4) << 2) + sunxi_gpio_info_t.pull_offset;

			bit_enable = 0;

			/* */if (PUD_UP == pud)
				bit_value = 1;
			else if (PUD_DOWN == pud)
				bit_value = 2;
			else if (PUD_OFF == pud)
				bit_value = 0;

			break;
	}

	/* Ignore unused gpio */
	if (ORANGEPI_PIN_MASK[bank][index] != -1)
	{
		if (wiringPiDebug)
			printf("bank: %d, index: %d\n", bank, index);

		regval = readR(phyaddr);

		if (wiringPiDebug)
			printf("read val(%#x) from register[%#x]\n", regval, phyaddr);

		/* clear bit */
		regval &= ~(3 << offset);

		/* bit write enable*/
		regval |= bit_enable;

		/* set bit */
		regval |= (bit_value & 3) << offset;

		if (wiringPiDebug)
			printf("write val(%#x) to register[%#x]\n", regval, phyaddr);

		writeR(regval, phyaddr);
		regval = readR(phyaddr);

		if (wiringPiDebug)
			printf("over reg val: %#x\n", regval);
	}
}
